mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE.
Gavin Sherry, Neil Conway, and Tom Lane all got their hands dirty on this one ...
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user