diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/view.c | 119 |
1 files changed, 86 insertions, 33 deletions
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index c635a28571d..46cdf0aca0b 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -6,43 +6,43 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: view.c,v 1.68 2002/08/30 19:23:19 tgl Exp $ + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.69 2002/09/02 02:13:01 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "access/xact.h" +#include "access/heapam.h" #include "catalog/dependency.h" -#include "catalog/heap.h" #include "catalog/namespace.h" #include "commands/tablecmds.h" #include "commands/view.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "parser/parse_relation.h" -#include "parser/parse_type.h" #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteManip.h" -#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteSupport.h" -#include "utils/syscache.h" +#include "utils/acl.h" +#include "utils/lsyscache.h" /*--------------------------------------------------------------------- * DefineVirtualRelation * - * Create the "view" relation. - * `DefineRelation' does all the work, we just provide the correct - * arguments! - * - * If the relation already exists, then 'DefineRelation' will abort - * the xact... + * Create the "view" relation. `DefineRelation' does all the work, + * we just provide the correct arguments ... at least when we're + * creating a view. If we're updating an existing view, we have to + * work harder. *--------------------------------------------------------------------- */ static Oid -DefineVirtualRelation(const RangeVar *relation, List *tlist) +DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) { + Oid viewOid, + namespaceId; CreateStmt *createStmt = makeNode(CreateStmt); List *attrList, *t; @@ -52,7 +52,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist) * the (non-junk) targetlist items from the view's SELECT list. */ attrList = NIL; - foreach(t, tlist) + foreach (t, tlist) { TargetEntry *entry = lfirst(t); Resdom *res = entry->resdom; @@ -83,23 +83,74 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist) elog(ERROR, "attempted to define virtual relation with no attrs"); /* - * now create the parameters for keys/inheritance etc. All of them are - * nil... + * Check to see if we want to replace an existing view. */ - createStmt->relation = (RangeVar *) relation; - createStmt->tableElts = attrList; - createStmt->inhRelations = NIL; - createStmt->constraints = NIL; - createStmt->hasoids = false; + namespaceId = RangeVarGetCreationNamespace(relation); + viewOid = get_relname_relid(relation->relname, namespaceId); - /* - * finally create the relation... - */ - return DefineRelation(createStmt, RELKIND_VIEW); + if (OidIsValid(viewOid) && replace) + { + Relation rel; + TupleDesc descriptor; + + /* + * Yes. Get exclusive lock on the existing view ... + */ + rel = relation_open(viewOid, AccessExclusiveLock); + + /* + * Make sure it *is* a view, and do permissions checks. + */ + if (rel->rd_rel->relkind != RELKIND_VIEW) + elog(ERROR, "%s is not a view", + RelationGetRelationName(rel)); + + if (!pg_class_ownercheck(viewOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel)); + + /* + * Create a tuple descriptor to compare against the existing view, + * and verify it matches. + * + * XXX the error message is a bit cheesy here: would be useful to + * give a more specific complaint about the difference in the + * descriptors. No time for it at the moment though. + */ + descriptor = BuildDescForRelation(attrList); + if (!equalTupleDescs(descriptor, rel->rd_att)) + elog(ERROR, "Cannot change column set of existing view %s", + RelationGetRelationName(rel)); + + /* + * Seems okay, so return the OID of the pre-existing view. + */ + relation_close(rel, NoLock); /* keep the lock! */ + + return viewOid; + } + else + { + /* + * now create the parameters for keys/inheritance etc. All of them are + * nil... + */ + createStmt->relation = (RangeVar *) relation; + createStmt->tableElts = attrList; + createStmt->inhRelations = NIL; + createStmt->constraints = NIL; + createStmt->hasoids = false; + + /* + * finally create the relation (this will error out if there's + * an existing view, so we don't need more code to complain + * if "replace" is false). + */ + return DefineRelation(createStmt, RELKIND_VIEW); + } } static RuleStmt * -FormViewRetrieveRule(const RangeVar *view, Query *viewParse) +FormViewRetrieveRule(const RangeVar *view, Query *viewParse, bool replace) { RuleStmt *rule; @@ -114,12 +165,13 @@ FormViewRetrieveRule(const RangeVar *view, Query *viewParse) rule->event = CMD_SELECT; rule->instead = true; rule->actions = makeList1(viewParse); + rule->replace = replace; return rule; } static void -DefineViewRules(const RangeVar *view, Query *viewParse) +DefineViewRules(const RangeVar *view, Query *viewParse, bool replace) { RuleStmt *retrieve_rule; @@ -129,10 +181,9 @@ DefineViewRules(const RangeVar *view, Query *viewParse) RuleStmt *delete_rule; #endif - retrieve_rule = FormViewRetrieveRule(view, viewParse); + retrieve_rule = FormViewRetrieveRule(view, viewParse, replace); #ifdef NOTYET - replace_rule = FormViewReplaceRule(view, viewParse); append_rule = FormViewAppendRule(view, viewParse); delete_rule = FormViewDeleteRule(view, viewParse); @@ -221,16 +272,18 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) *------------------------------------------------------------------- */ void -DefineView(const RangeVar *view, Query *viewParse) +DefineView(const RangeVar *view, Query *viewParse, bool replace) { Oid viewOid; /* * Create the view relation * - * NOTE: if it already exists, the xact will be aborted. + * NOTE: if it already exists and replace is false, the xact will + * be aborted. */ - viewOid = DefineVirtualRelation(view, viewParse->targetList); + + viewOid = DefineVirtualRelation(view, viewParse->targetList, replace); /* * The relation we have just created is not visible to any other @@ -248,7 +301,7 @@ DefineView(const RangeVar *view, Query *viewParse) /* * Now create the rules associated with the view. */ - DefineViewRules(view, viewParse); + DefineViewRules(view, viewParse, replace); } /* |