This patch implements a different "relkind"
authorBruce Momjian <[email protected]>
Tue, 12 Sep 2000 04:49:17 +0000 (04:49 +0000)
committerBruce Momjian <[email protected]>
Tue, 12 Sep 2000 04:49:17 +0000 (04:49 +0000)
for views. Views are now have a "relkind" of
RELKIND_VIEW instead of RELKIND_RELATION.

Also, views no longer have actual heap storage
files.

The following changes were made

1. CREATE VIEW sets the new relkind

2. The executor complains if a DELETE or
        INSERT references a view.

3. DROP RULE complains if an attempt is made
        to delete a view SELECT rule.

4. CREATE RULE "_RETmytable" AS ON SELECT TO mytable DO INSTEAD ...
        1. checks to make sure mytable is empty.
        2. sets the relkind to RELKIND_VIEW.
        3. deletes the heap storage files.
5. LOCK myview is not allowed. :)

6. the regression test type_sanity was changed to
        account for the new relkind value.

7. CREATE INDEX ON myview ... is not allowed.

8. VACUUM myview is not allowed.
        VACUUM automatically skips views when do the entire
        database.

9. TRUNCATE myview is not allowed.

THINGS LEFT TO THINK ABOUT

o pg_views

o pg_dump

o pgsql (\d \dv)
o Do we really want to be able to inherit from views?

o Is 'DROP TABLE myview' OK?

--
Mark Hollomon

14 files changed:
src/backend/catalog/heap.c
src/backend/commands/command.c
src/backend/commands/comment.c
src/backend/commands/vacuum.c
src/backend/commands/view.c
src/backend/executor/execMain.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteRemove.c
src/backend/tcop/utility.c
src/backend/utils/cache/relcache.c
src/include/catalog/catversion.h
src/include/catalog/pg_class.h
src/test/regress/expected/type_sanity.out
src/test/regress/sql/type_sanity.sql

index cf4b86e2e82cca3dfe0df06020584ccb2bb01b54..68bb8276981568f3c9ed3c4cded35f1ba725d309 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.142 2000/08/03 19:19:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.143 2000/09/12 04:49:06 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -842,7 +842,9 @@ heap_create_with_catalog(char *relname,
        /*
         * We create the disk file for this relation here
         */
-       heap_storage_create(new_rel_desc);
+       if (relkind != RELKIND_VIEW)
+               heap_storage_create(new_rel_desc);
+
        /* ----------------
         *      ok, the relation has been cataloged, so close our relations
         *      and return the oid of the newly created relation.
@@ -1468,7 +1470,7 @@ heap_drop_with_catalog(const char *relname,
         *      unlink the relation's physical file and finish up.
         * ----------------
         */
-       if (! rel->rd_unlinked)
+       if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_unlinked)
                smgrunlink(DEFAULT_SMGR, rel);
        rel->rd_unlinked = true;
 
index d0de9e2e4de68b9181de841319e5475d77dfbd59..d0faa943cfd620047e0b8d293ea3ad3abbeacd68 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.100 2000/09/12 04:33:18 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.101 2000/09/12 04:49:06 momjian Exp $
  *
  * NOTES
  *       The PerformAddAttribute() code, like most of the relation
@@ -533,6 +533,9 @@ AlterTableAlterColumn(const char *relationName,
 #endif
 
        rel = heap_openr(relationName, AccessExclusiveLock);
+       if ( rel->rd_rel->relkind == RELKIND_VIEW )
+               elog(ERROR, "ALTER TABLE: %s is a view", relationName);
+
        myrelid = RelationGetRelid(rel);
        heap_close(rel, NoLock);
 
@@ -1133,6 +1136,10 @@ AlterTableAddConstraint(char *relationName,
 
                                                rel = heap_openr(relationName, AccessExclusiveLock);
 
+                                               /* make sure it is not a view */
+                                               if (rel->rd_rel->relkind == RELKIND_VIEW)
+                                                  elog(ERROR, "ALTER TABLE: cannot add constraint to a view");
+
                                                /*
                                                 * Scan all of the rows, looking for a false match
                                                 */
@@ -1251,19 +1258,20 @@ AlterTableAddConstraint(char *relationName,
                                        elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
                                }
 
-                               /* check to see if the referenced table is a view. */
-                               if (is_viewr(fkconstraint->pktable_name))
-                                elog(ERROR, "ALTER TABLE: Cannot add constraints to views.");
-
                                /*
                                 * Grab an exclusive lock on the pk table, so that someone
                                 * doesn't delete rows out from under us.
                                 */
 
                                pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
-                               if (pkrel == NULL)
-                                       elog(ERROR, "referenced table \"%s\" not found",
+                               if (pkrel == NULL)
+                                               elog(ERROR, "referenced table \"%s\" not found",
+                                                        fkconstraint->pktable_name);
+
+                               if (pkrel->rd_rel->relkind != RELKIND_RELATION)
+                                       elog(ERROR, "referenced table \"%s\" not a relation", 
                                         fkconstraint->pktable_name);
+                               
 
                                /*
                                 * Grab an exclusive lock on the fk table, and then scan
@@ -1277,6 +1285,9 @@ AlterTableAddConstraint(char *relationName,
                                        elog(ERROR, "table \"%s\" not found",
                                                relationName);
 
+                               if (rel->rd_rel->relkind != RELKIND_RELATION)
+                                       elog(ERROR, "referencing table \"%s\" not a relation", relationName);
+
                                /* First we check for limited correctness of the constraint */
 
                                rel_attrs = pkrel->rd_att->attrs;
@@ -1503,6 +1514,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
         * allow to create TOAST tables for views. But why not - someone
         * can insert into a view, so it shouldn't be impossible to hide
         * huge data there :-)
+        * Not any more.
         */
        if (((Form_pg_class) GETSTRUCT(reltup))->relkind != RELKIND_RELATION)
        {
@@ -1702,6 +1714,9 @@ LockTableCommand(LockStmt *lockstmt)
 
        rel = heap_openr(lockstmt->relname, NoLock);
 
+       if (rel->rd_rel->relkind != RELKIND_RELATION)
+                       elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);
+
        if (is_view(rel)) 
                        elog(ERROR, "LOCK TABLE: cannot lock a view");
 
index 87c7d84727ddb1b0d0ff0282e31dbbdec8cd0617..51832bc2c7bb442a78f261801d130ee8d37dc9fc 100644 (file)
@@ -21,6 +21,7 @@
 #include "catalog/pg_shadow.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_class.h"
 #include "commands/comment.h"
 #include "miscadmin.h"
 #include "parser/parse.h"
@@ -301,19 +302,19 @@ CommentRelation(int reltype, char *relname, char *comment)
        switch (reltype)
        {
                case (INDEX):
-                       if (relkind != 'i')
+                       if (relkind != RELKIND_INDEX)
                                elog(ERROR, "relation '%s' is not an index", relname);
                        break;
                case (TABLE):
-                       if (relkind != 'r')
+                       if (relkind != RELKIND_RELATION)
                                elog(ERROR, "relation '%s' is not a table", relname);
                        break;
                case (VIEW):
-                       if (relkind != 'r')
+                       if (relkind != RELKIND_VIEW)
                                elog(ERROR, "relation '%s' is not a view", relname);
                        break;
                case (SEQUENCE):
-                       if (relkind != 'S')
+                       if (relkind != RELKIND_SEQUENCE)
                                elog(ERROR, "relation '%s' is not a sequence", relname);
                        break;
        }
index 398d002ffcd2ad28460add27af2c528a7e77261a..7d4005d21d5b5d953cc4a4cacafa547f10fd1591 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.164 2000/09/06 14:15:16 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.165 2000/09/12 04:49:07 momjian Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -306,7 +306,7 @@ getrels(NameData *VacRelP)
 
                if (rkind != RELKIND_RELATION)
                {
-                       elog(NOTICE, "Vacuum: can not process index and certain system tables");
+                       elog(NOTICE, "Vacuum: can not process indecies, views and certain system tables");
                        continue;
                }
 
index 01e23d13150268d811efd2a2d0396a1ac59a45da..af10805b71f39f28ff843257c21217c60cfe8970 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: view.c,v 1.46 2000/09/12 04:15:56 momjian Exp $
+ *     $Id: view.c,v 1.47 2000/09/12 04:49:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,7 +102,7 @@ DefineVirtualRelation(char *relname, List *tlist)
        /*
         * finally create the relation...
         */
-       DefineRelation(&createStmt, RELKIND_RELATION);
+       DefineRelation(&createStmt, RELKIND_VIEW);
 }
 
 /*------------------------------------------------------------------
index c6571279e1f418fbbe045d21c0ee26b57ff13481..d25530b44fb9d0e7219f828cd443b5c346676b00 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.125 2000/09/06 14:15:17 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.126 2000/09/12 04:49:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -720,6 +720,10 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
                        elog(ERROR, "You can't change toast relation %s",
                                 RelationGetRelationName(resultRelationDesc));
 
+               if (resultRelationDesc->rd_rel->relkind == RELKIND_VIEW)
+                       elog(ERROR, "You can't change view relation %s",
+                                RelationGetRelationName(resultRelationDesc));
+
                resultRelationInfo = makeNode(RelationInfo);
                resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
                resultRelationInfo->ri_RelationDesc = resultRelationDesc;
index c9315f6d338fc79d2cca32da0509c6901a47077e..8444bd9138423c985097d50837ba4087c393507a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.50 2000/09/12 04:15:57 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.51 2000/09/12 04:49:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,8 @@
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteSupport.h"
+#include "utils/syscache.h"
+#include "storage/smgr.h"
 #include "commands/view.h"
 
 
@@ -162,6 +164,7 @@ DefineQueryRewrite(RuleStmt *stmt)
                           *event_qualP;
        List       *l;
        Query      *query;
+       bool            RelisBecomingView = false;
 
        /*
         * If we are installing an ON SELECT rule, we had better grab
@@ -207,6 +210,30 @@ DefineQueryRewrite(RuleStmt *stmt)
                        elog(ERROR, "rule actions on NEW currently not supported"
                                 "\n\tuse triggers instead");
                }
+
+               if (event_relation->rd_rel->relkind != RELKIND_VIEW)
+               {
+                       HeapScanDesc  scanDesc;
+                       HeapTuple         tuple;
+                       /*
+                        * A relation is about to become a view.
+                        * check that the relation is empty because
+                        * the storage for the relation is going to
+                        * be deleted.
+                        */
+
+                       scanDesc = heap_beginscan(event_relation, 0, SnapshotNow, 0, NULL);
+                       tuple = heap_getnext(scanDesc, 0);
+                       if (HeapTupleIsValid(tuple))
+                               elog(ERROR, "relation %s is not empty. Cannot convert to view", event_obj->relname);
+
+                       /* don't need heap_freetuple because we never got a valid tuple */
+                       heap_endscan(scanDesc);
+
+
+                       RelisBecomingView = true;
+               }
+
        }
 
        /*
@@ -338,6 +365,10 @@ DefineQueryRewrite(RuleStmt *stmt)
        /* discard rule if it's null action and not INSTEAD; it's a no-op */
        if (action != NULL || is_instead)
        {
+               Relation        relationRelation;
+               HeapTuple       tuple;
+               Relation        idescs[Num_pg_class_indices];
+
                event_qualP = nodeToString(event_qual);
                actionP = nodeToString(action);
 
@@ -351,14 +382,50 @@ DefineQueryRewrite(RuleStmt *stmt)
 
                /*
                 * Set pg_class 'relhasrules' field TRUE for event relation.
+                * Also modify the 'relkind' field to show that the relation is
+                * now a view.
                 *
                 * Important side effect: an SI notice is broadcast to force all
                 * backends (including me!) to update relcache entries with the new
                 * rule.
+                *
+                * NOTE : Used to call setRelhasrulesInRelation. The code
+                * was inlined so that two updates were not needed. mhh 31-aug-2000
+                */
+
+               /*
+                * Find the tuple to update in pg_class, using syscache for the lookup.
                 */
-               setRelhasrulesInRelation(ev_relid, true);
+               relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+               tuple = SearchSysCacheTupleCopy(RELOID,
+                                                                       ObjectIdGetDatum(ev_relid),
+                                                                       0, 0, 0);
+               Assert(HeapTupleIsValid(tuple));
+
+               /* Do the update */
+               ((Form_pg_class) GETSTRUCT(tuple))->relhasrules = true;
+               if (RelisBecomingView)
+                       ((Form_pg_class) GETSTRUCT(tuple))->relkind = RELKIND_VIEW;
+
+               heap_update(relationRelation, &tuple->t_self, tuple, NULL);
+
+               /* Keep the catalog indices up to date */
+               CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+               CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
+               CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+               heap_freetuple(tuple);
+               heap_close(relationRelation, RowExclusiveLock);
        }
 
+       /*
+        * IF the relation is becoming a view, delete the storage
+        * files associated with it.
+        */
+       if (RelisBecomingView)
+               smgrunlink(DEFAULT_SMGR, event_relation);
+
+
        /* Close rel, but keep lock till commit... */
        heap_close(event_relation, NoLock);
 }
index d50e1049097bbe006df356f111b38e0dd71214eb..2af77853c467a46add7bdcb54ee6c8c525479212 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.38 2000/06/30 07:04:23 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.39 2000/09/12 04:49:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -103,6 +103,11 @@ RemoveRewriteRule(char *ruleName)
         */
        event_relation = heap_open(eventRelationOid, AccessExclusiveLock);
 
+       /* do not allow the removal of a view's SELECT rule */
+       if (event_relation->rd_rel->relkind == RELKIND_VIEW &&
+                       ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_type == '1' )
+               elog(ERROR, "Cannot remove a view's SELECT rule");
+
        hasMoreRules = event_relation->rd_rules != NULL &&
                event_relation->rd_rules->numLocks > 1;
 
index 558f678430ff71d35cfacab9e7900b2a312f273e..d603914c514a65f46e13436b258ad59260621b22 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.92 2000/09/06 14:15:21 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.93 2000/09/12 04:49:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -228,6 +228,9 @@ ProcessUtility(Node *parsetree,
                                if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                                        elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
                                                 relname);
+                               if (rel->rd_rel->relkind == RELKIND_VIEW)
+                                       elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a sequence",
+                                                relname);
                                heap_close(rel, NoLock);
 
 #ifndef NO_SECURITY
index 013ade75288000c6332d49da1eca616989d39c9c..e39f1cfd12d4b7b71ccf7763f368342b0cd8f6ed 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.110 2000/08/30 08:48:55 inoue Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.111 2000/09/12 04:49:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1022,14 +1022,18 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
         *      by the storage manager code to rd_fd.
         * ----------------
         */
-       fd = smgropen(DEFAULT_SMGR, relation);
+       if (relation->rd_rel->relkind != RELKIND_VIEW) {
+               fd = smgropen(DEFAULT_SMGR, relation);
 
-       Assert(fd >= -1);
-       if (fd == -1)
-               elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
-                        NameStr(relation->rd_rel->relname));
+               Assert(fd >= -1);
+               if (fd == -1)
+                       elog(NOTICE, "RelationBuildDesc: smgropen(%s): %m",
+                                NameStr(relation->rd_rel->relname));
 
-       relation->rd_fd = fd;
+               relation->rd_fd = fd;
+       } else {
+               relation->rd_fd = -1;
+       }
 
        /* ----------------
         *      insert newly created relation into proper relcaches,
@@ -1279,7 +1283,7 @@ RelationIdCacheGetRelation(Oid relationId)
 
        if (RelationIsValid(rd))
        {
-               if (rd->rd_fd == -1)
+               if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
                {
                        rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
                        Assert(rd->rd_fd != -1 || rd->rd_unlinked);
@@ -1313,7 +1317,7 @@ RelationNameCacheGetRelation(const char *relationName)
 
        if (RelationIsValid(rd))
        {
-               if (rd->rd_fd == -1)
+               if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
                {
                        rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
                        Assert(rd->rd_fd != -1 || rd->rd_unlinked);
index 22b3cb7354ede6ca351367a7f1289d284f5577f7..b73ea0e6136e105db47812d3f8c3471aa10fea39 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.43 2000/08/23 06:04:43 thomas Exp $
+ * $Id: catversion.h,v 1.44 2000/09/12 04:49:15 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200008221
+#define CATALOG_VERSION_NO     200009111
 
 #endif
index 1ea5b7b7792f96781d0518a788f8eaf4af420a65..3fc4a7fd76cc3febf1df81be65eff4a43b25491b 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.39 2000/07/03 23:10:05 wieck Exp $
+ * $Id: pg_class.h,v 1.40 2000/09/12 04:49:15 momjian Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -178,5 +178,6 @@ DESCR("");
 #define                  RELKIND_SEQUENCE                'S'           /* SEQUENCE relation */
 #define                  RELKIND_UNCATALOGED     'u'           /* temporary heap */
 #define                  RELKIND_TOASTVALUE      't'           /* moved off huge values */
+#define                  RELKIND_VIEW                          'v'     /* view */
 
 #endif  /* PG_CLASS_H */
index 38eaf0b21dad6d544f6e7ade125c559944996a51..4f388b0e456016de12e5594d4947d7da5a5456a0 100644 (file)
@@ -111,7 +111,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype = 'b' AND
 -- Look for illegal values in pg_class fields
 SELECT p1.oid, p1.relname
 FROM pg_class as p1
-WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't');
+WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
  oid | relname 
 -----+---------
 (0 rows)
index 106a86b87c8c9df9ccbe844d39bc1c52fa74ee72..dbd6d0af409695b7f1a2fa7c5240aa52a4f53be8 100644 (file)
@@ -99,7 +99,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype = 'b' AND
 
 SELECT p1.oid, p1.relname
 FROM pg_class as p1
-WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't');
+WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
 
 -- Indexes should have an access method, others not.