aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/view.c119
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);
}
/*