diff -cr pgsql.orig/src/backend/catalog/heap.c pgsql/src/backend/catalog/heap.c *** pgsql.orig/src/backend/catalog/heap.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/catalog/heap.c Thu Aug 31 02:35:42 2000 *************** *** 842,848 **** /* * We create the disk file for this relation here */ ! 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. --- 842,850 ---- /* * We create the disk file for this relation here */ ! 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,1474 **** * unlink the relation's physical file and finish up. * ---------------- */ ! if (! rel->rd_unlinked) smgrunlink(DEFAULT_SMGR, rel); rel->rd_unlinked = true; --- 1470,1476 ---- * unlink the relation's physical file and finish up. * ---------------- */ ! if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_unlinked) smgrunlink(DEFAULT_SMGR, rel); rel->rd_unlinked = true; diff -cr pgsql.orig/src/backend/commands/command.c pgsql/src/backend/commands/command.c *** pgsql.orig/src/backend/commands/command.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/commands/command.c Wed Aug 30 20:57:13 2000 *************** *** 528,533 **** --- 528,536 ---- #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); *************** *** 1087,1095 **** AlterTableAddConstraint(char *relationName, bool inh, Node *newConstraint) { - char rulequery[41+NAMEDATALEN]; - void *qplan; - char nulls[1]=""; if (newConstraint == NULL) elog(ERROR, "ALTER TABLE / ADD CONSTRAINT passed invalid constraint."); --- 1090,1095 ---- *************** *** 1099,1119 **** elog(ERROR, "ALTER TABLE: permission denied"); #endif - /* check to see if the table to be constrained is a view. */ - sprintf(rulequery, "select * from pg_views where viewname='%s'", relationName); - if (SPI_connect()!=SPI_OK_CONNECT) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_connect failure..", relationName); - qplan=SPI_prepare(rulequery, 0, NULL); - if (!qplan) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_prepare failure.", relationName); - qplan=SPI_saveplan(qplan); - if (SPI_execp(qplan, NULL, nulls, 1)!=SPI_OK_SELECT) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view - SPI_execp failure.", relationName); - if (SPI_processed != 0) - elog(ERROR, "ALTER TABLE: Cannot add constraints to views."); - if (SPI_finish() != SPI_OK_FINISH) - elog(NOTICE, "SPI_finish() failed in ALTER TABLE"); - switch (nodeTag(newConstraint)) { case T_Constraint: --- 1099,1104 ---- *************** *** 1142,1147 **** --- 1127,1136 ---- 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 */ *************** *** 1260,1279 **** 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. */ - sprintf(rulequery, "select * from pg_views where viewname='%s'", fkconstraint->pktable_name); - if (SPI_connect()!=SPI_OK_CONNECT) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); - qplan=SPI_prepare(rulequery, 0, NULL); - if (!qplan) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); - qplan=SPI_saveplan(qplan); - if (SPI_execp(qplan, NULL, nulls, 1)!=SPI_OK_SELECT) - elog(ERROR, "ALTER TABLE: Unable to determine if %s is a view.", relationName); - if (SPI_processed != 0) - elog(ERROR, "ALTER TABLE: Cannot add constraints to views."); - if (SPI_finish() != SPI_OK_FINISH) - elog(NOTICE, "SPI_finish() failed in RI_FKey_check()"); /* * Grab an exclusive lock on the pk table, so that someone --- 1249,1254 ---- *************** *** 1281,1289 **** */ pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock); ! if (pkrel == NULL) ! elog(ERROR, "referenced table \"%s\" not found", fkconstraint->pktable_name); /* * Grab an exclusive lock on the fk table, and then scan --- 1256,1269 ---- */ pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock); ! 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 *************** *** 1297,1302 **** --- 1277,1285 ---- 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; *************** *** 1523,1528 **** --- 1506,1512 ---- * 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) { *************** *** 1721,1726 **** --- 1705,1713 ---- int aclresult; 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 (lockstmt->mode == AccessShareLock) aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_RD); diff -cr pgsql.orig/src/backend/commands/comment.c pgsql/src/backend/commands/comment.c *** pgsql.orig/src/backend/commands/comment.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/commands/comment.c Wed Aug 30 17:08:50 2000 *************** *** 21,26 **** --- 21,27 ---- #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,319 **** switch (reltype) { case (INDEX): ! if (relkind != 'i') elog(ERROR, "relation '%s' is not an index", relname); break; case (TABLE): ! if (relkind != 'r') elog(ERROR, "relation '%s' is not a table", relname); break; case (VIEW): ! if (relkind != 'r') elog(ERROR, "relation '%s' is not a view", relname); break; case (SEQUENCE): ! if (relkind != 'S') elog(ERROR, "relation '%s' is not a sequence", relname); break; } --- 302,320 ---- switch (reltype) { case (INDEX): ! if (relkind != RELKIND_INDEX) elog(ERROR, "relation '%s' is not an index", relname); break; case (TABLE): ! if (relkind != RELKIND_RELATION) elog(ERROR, "relation '%s' is not a table", relname); break; case (VIEW): ! if (relkind != RELKIND_VIEW) elog(ERROR, "relation '%s' is not a view", relname); break; case (SEQUENCE): ! if (relkind != RELKIND_SEQUENCE) elog(ERROR, "relation '%s' is not a sequence", relname); break; } diff -cr pgsql.orig/src/backend/commands/vacuum.c pgsql/src/backend/commands/vacuum.c *** pgsql.orig/src/backend/commands/vacuum.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/commands/vacuum.c Wed Aug 30 17:35:55 2000 *************** *** 306,312 **** if (rkind != RELKIND_RELATION) { ! elog(NOTICE, "Vacuum: can not process index and certain system tables"); continue; } --- 306,312 ---- if (rkind != RELKIND_RELATION) { ! elog(NOTICE, "Vacuum: can not process indecies, views and certain system tables"); continue; } diff -cr pgsql.orig/src/backend/commands/view.c pgsql/src/backend/commands/view.c *** pgsql.orig/src/backend/commands/view.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/commands/view.c Wed Aug 30 18:45:48 2000 *************** *** 102,108 **** /* * finally create the relation... */ ! DefineRelation(&createStmt, RELKIND_RELATION); } /*------------------------------------------------------------------ --- 102,108 ---- /* * finally create the relation... */ ! DefineRelation(&createStmt, RELKIND_VIEW); } /*------------------------------------------------------------------ diff -cr pgsql.orig/src/backend/executor/execMain.c pgsql/src/backend/executor/execMain.c *** pgsql.orig/src/backend/executor/execMain.c Tue Aug 29 21:36:23 2000 --- pgsql/src/backend/executor/execMain.c Wed Aug 30 18:11:10 2000 *************** *** 720,725 **** --- 720,729 ---- 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 -cr pgsql.orig/src/backend/rewrite/rewriteDefine.c pgsql/src/backend/rewrite/rewriteDefine.c *** pgsql.orig/src/backend/rewrite/rewriteDefine.c Tue Aug 29 21:36:28 2000 --- pgsql/src/backend/rewrite/rewriteDefine.c Thu Aug 31 09:08:01 2000 *************** *** 23,28 **** --- 23,30 ---- #include "parser/parse_relation.h" #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteSupport.h" + #include "utils/syscache.h" + #include "storage/smgr.h" /* *************** *** 161,166 **** --- 163,169 ---- *event_qualP; List *l; Query *query; + bool RelisBecomingView = false; /* * If we are installing an ON SELECT rule, we had better grab *************** *** 311,316 **** --- 314,343 ---- elog(ERROR, "view rule for %s must be named %s", event_obj->relname, expected_name); } + + 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; + } + } /* *************** *** 335,340 **** --- 362,371 ---- /* 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); *************** *** 348,360 **** /* * Set pg_class 'relhasrules' field TRUE for event relation. * * Important side effect: an SI notice is broadcast to force all * backends (including me!) to update relcache entries with the new * rule. */ ! setRelhasrulesInRelation(ev_relid, true); } /* Close rel, but keep lock till commit... */ heap_close(event_relation, NoLock); --- 379,427 ---- /* * 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. ! */ ! 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 -cr pgsql.orig/src/backend/rewrite/rewriteRemove.c pgsql/src/backend/rewrite/rewriteRemove.c *** pgsql.orig/src/backend/rewrite/rewriteRemove.c Tue Aug 29 21:36:28 2000 --- pgsql/src/backend/rewrite/rewriteRemove.c Thu Aug 31 09:20:34 2000 *************** *** 103,108 **** --- 103,113 ---- */ 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 -cr pgsql.orig/src/backend/tcop/utility.c pgsql/src/backend/tcop/utility.c *** pgsql.orig/src/backend/tcop/utility.c Tue Aug 29 21:36:29 2000 --- pgsql/src/backend/tcop/utility.c Wed Aug 30 18:30:30 2000 *************** *** 231,236 **** --- 231,239 ---- 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 -cr pgsql.orig/src/backend/utils/cache/relcache.c pgsql/src/backend/utils/cache/relcache.c *** pgsql.orig/src/backend/utils/cache/relcache.c Thu Aug 31 11:26:20 2000 --- pgsql/src/backend/utils/cache/relcache.c Thu Aug 31 02:39:55 2000 *************** *** 1022,1035 **** * by the storage manager code to rd_fd. * ---------------- */ ! fd = smgropen(DEFAULT_SMGR, relation); ! Assert(fd >= -1); ! if (fd == -1) ! elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m", ! NameStr(relation->rd_rel->relname)); ! ! relation->rd_fd = fd; /* ---------------- * insert newly created relation into proper relcaches, --- 1022,1039 ---- * by the storage manager code to rd_fd. * ---------------- */ ! if (relation->rd_rel->relkind != RELKIND_VIEW) { ! fd = smgropen(DEFAULT_SMGR, relation); ! Assert(fd >= -1); ! if (fd == -1) ! elog(NOTICE, "RelationBuildDesc: smgropen(%s): %m", ! NameStr(relation->rd_rel->relname)); ! ! relation->rd_fd = fd; ! } else { ! relation->rd_fd = -1; ! } /* ---------------- * insert newly created relation into proper relcaches, *************** *** 1279,1285 **** if (RelationIsValid(rd)) { ! if (rd->rd_fd == -1) { rd->rd_fd = smgropen(DEFAULT_SMGR, rd); Assert(rd->rd_fd != -1 || rd->rd_unlinked); --- 1283,1289 ---- if (RelationIsValid(rd)) { ! 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,1319 **** if (RelationIsValid(rd)) { ! if (rd->rd_fd == -1) { rd->rd_fd = smgropen(DEFAULT_SMGR, rd); Assert(rd->rd_fd != -1 || rd->rd_unlinked); --- 1317,1323 ---- if (RelationIsValid(rd)) { ! 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 -cr pgsql.orig/src/include/catalog/pg_class.h pgsql/src/include/catalog/pg_class.h *** pgsql.orig/src/include/catalog/pg_class.h Tue Aug 29 21:36:39 2000 --- pgsql/src/include/catalog/pg_class.h Wed Aug 30 16:49:00 2000 *************** *** 178,182 **** --- 178,183 ---- #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 -cr pgsql.orig/src/test/regress/expected/type_sanity.out pgsql/src/test/regress/expected/type_sanity.out *** pgsql.orig/src/test/regress/expected/type_sanity.out Tue Aug 29 21:37:09 2000 --- pgsql/src/test/regress/expected/type_sanity.out Thu Aug 31 09:37:36 2000 *************** *** 111,117 **** -- 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'); oid | relname -----+--------- (0 rows) --- 111,117 ---- -- 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', 'v'); oid | relname -----+--------- (0 rows) diff -cr pgsql.orig/src/test/regress/sql/type_sanity.sql pgsql/src/test/regress/sql/type_sanity.sql *** pgsql.orig/src/test/regress/sql/type_sanity.sql Tue Aug 29 21:37:03 2000 --- pgsql/src/test/regress/sql/type_sanity.sql Thu Aug 31 09:34:26 2000 *************** *** 99,105 **** SELECT p1.oid, p1.relname FROM pg_class as p1 ! WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't'); -- Indexes should have an access method, others not. --- 99,105 ---- SELECT p1.oid, p1.relname FROM pg_class as p1 ! WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v'); -- Indexes should have an access method, others not.