This patch implements a different "relkind"

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
This commit is contained in:
Bruce Momjian 2000-09-12 04:49:17 +00:00
parent c0af8babe3
commit 264c068207
14 changed files with 139 additions and 37 deletions

View 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;

View 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");

View 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;
}

View 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;
}

View 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);
}
/*------------------------------------------------------------------

View 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;

View 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
*/
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);
}

View 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;

View 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

View 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);

View 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

View 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 */

View 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)

View 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.