diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index cf4b86e2e8..68bb827698 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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; diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index d0de9e2e4d..d0faa943cf 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -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"); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 87c7d84727..51832bc2c7 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -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; } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 398d002ffc..7d4005d21d 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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; } diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 01e23d1315..af10805b71 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -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); } /*------------------------------------------------------------------ diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index c6571279e1..d25530b44f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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; diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index c9315f6d33..8444bd9138 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -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 */ - setRelhasrulesInRelation(ev_relid, true); + + /* + * Find the tuple to update in pg_class, using syscache for the lookup. + */ + 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); } diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index d50e104909..2af77853c4 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -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; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 558f678430..d603914c51 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -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 diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 013ade7528..e39f1cfd12 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 22b3cb7354..b73ea0e613 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 1ea5b7b779..3fc4a7fd76 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -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 */ diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 38eaf0b21d..4f388b0e45 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -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) diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 106a86b87c..dbd6d0af40 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -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.