OSDN Git Service

This patch implements a different "relkind"
authorBruce Momjian <bruce@momjian.us>
Tue, 12 Sep 2000 04:49:17 +0000 (04:49 +0000)
committerBruce Momjian <bruce@momjian.us>
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 cf4b86e..68bb827 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 d0de9e2..d0faa94 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 87c7d84..51832bc 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 398d002..7d4005d 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 01e23d1..af10805 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 c657127..d25530b 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 c9315f6..8444bd9 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 d50e104..2af7785 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 558f678..d603914 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 013ade7..e39f1cf 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 22b3cb7..b73ea0e 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 1ea5b7b..3fc4a7f 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 38eaf0b..4f388b0 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 106a86b..dbd6d0a 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.