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:
parent
c7a165adc6
commit
248c67d7ed
@ -6,43 +6,43 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 "postgres.h"
|
||||||
|
|
||||||
#include "access/xact.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/heap.h"
|
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/view.h"
|
#include "commands/view.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "parser/parse_type.h"
|
|
||||||
#include "rewrite/rewriteDefine.h"
|
#include "rewrite/rewriteDefine.h"
|
||||||
#include "rewrite/rewriteManip.h"
|
#include "rewrite/rewriteManip.h"
|
||||||
#include "rewrite/rewriteRemove.h"
|
|
||||||
#include "rewrite/rewriteSupport.h"
|
#include "rewrite/rewriteSupport.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/acl.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------
|
/*---------------------------------------------------------------------
|
||||||
* DefineVirtualRelation
|
* DefineVirtualRelation
|
||||||
*
|
*
|
||||||
* Create the "view" relation.
|
* Create the "view" relation. `DefineRelation' does all the work,
|
||||||
* `DefineRelation' does all the work, we just provide the correct
|
* we just provide the correct arguments ... at least when we're
|
||||||
* arguments!
|
* creating a view. If we're updating an existing view, we have to
|
||||||
*
|
* work harder.
|
||||||
* If the relation already exists, then 'DefineRelation' will abort
|
|
||||||
* the xact...
|
|
||||||
*---------------------------------------------------------------------
|
*---------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static Oid
|
static Oid
|
||||||
DefineVirtualRelation(const RangeVar *relation, List *tlist)
|
DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
|
||||||
{
|
{
|
||||||
|
Oid viewOid,
|
||||||
|
namespaceId;
|
||||||
CreateStmt *createStmt = makeNode(CreateStmt);
|
CreateStmt *createStmt = makeNode(CreateStmt);
|
||||||
List *attrList,
|
List *attrList,
|
||||||
*t;
|
*t;
|
||||||
@ -52,7 +52,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist)
|
|||||||
* the (non-junk) targetlist items from the view's SELECT list.
|
* the (non-junk) targetlist items from the view's SELECT list.
|
||||||
*/
|
*/
|
||||||
attrList = NIL;
|
attrList = NIL;
|
||||||
foreach(t, tlist)
|
foreach (t, tlist)
|
||||||
{
|
{
|
||||||
TargetEntry *entry = lfirst(t);
|
TargetEntry *entry = lfirst(t);
|
||||||
Resdom *res = entry->resdom;
|
Resdom *res = entry->resdom;
|
||||||
@ -82,6 +82,54 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist)
|
|||||||
if (attrList == NIL)
|
if (attrList == NIL)
|
||||||
elog(ERROR, "attempted to define virtual relation with no attrs");
|
elog(ERROR, "attempted to define virtual relation with no attrs");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if we want to replace an existing view.
|
||||||
|
*/
|
||||||
|
namespaceId = RangeVarGetCreationNamespace(relation);
|
||||||
|
viewOid = get_relname_relid(relation->relname, namespaceId);
|
||||||
|
|
||||||
|
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
|
* now create the parameters for keys/inheritance etc. All of them are
|
||||||
* nil...
|
* nil...
|
||||||
@ -93,13 +141,16 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist)
|
|||||||
createStmt->hasoids = false;
|
createStmt->hasoids = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finally create the relation...
|
* 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);
|
return DefineRelation(createStmt, RELKIND_VIEW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RuleStmt *
|
static RuleStmt *
|
||||||
FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
|
FormViewRetrieveRule(const RangeVar *view, Query *viewParse, bool replace)
|
||||||
{
|
{
|
||||||
RuleStmt *rule;
|
RuleStmt *rule;
|
||||||
|
|
||||||
@ -114,12 +165,13 @@ FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
|
|||||||
rule->event = CMD_SELECT;
|
rule->event = CMD_SELECT;
|
||||||
rule->instead = true;
|
rule->instead = true;
|
||||||
rule->actions = makeList1(viewParse);
|
rule->actions = makeList1(viewParse);
|
||||||
|
rule->replace = replace;
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DefineViewRules(const RangeVar *view, Query *viewParse)
|
DefineViewRules(const RangeVar *view, Query *viewParse, bool replace)
|
||||||
{
|
{
|
||||||
RuleStmt *retrieve_rule;
|
RuleStmt *retrieve_rule;
|
||||||
|
|
||||||
@ -129,10 +181,9 @@ DefineViewRules(const RangeVar *view, Query *viewParse)
|
|||||||
RuleStmt *delete_rule;
|
RuleStmt *delete_rule;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
retrieve_rule = FormViewRetrieveRule(view, viewParse);
|
retrieve_rule = FormViewRetrieveRule(view, viewParse, replace);
|
||||||
|
|
||||||
#ifdef NOTYET
|
#ifdef NOTYET
|
||||||
|
|
||||||
replace_rule = FormViewReplaceRule(view, viewParse);
|
replace_rule = FormViewReplaceRule(view, viewParse);
|
||||||
append_rule = FormViewAppendRule(view, viewParse);
|
append_rule = FormViewAppendRule(view, viewParse);
|
||||||
delete_rule = FormViewDeleteRule(view, viewParse);
|
delete_rule = FormViewDeleteRule(view, viewParse);
|
||||||
@ -221,16 +272,18 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
|
|||||||
*-------------------------------------------------------------------
|
*-------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
DefineView(const RangeVar *view, Query *viewParse)
|
DefineView(const RangeVar *view, Query *viewParse, bool replace)
|
||||||
{
|
{
|
||||||
Oid viewOid;
|
Oid viewOid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the view relation
|
* 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
|
* 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.
|
* Now create the rules associated with the view.
|
||||||
*/
|
*/
|
||||||
DefineViewRules(view, viewParse);
|
DefineViewRules(view, viewParse, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.209 2002/08/31 22:10:43 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.210 2002/09/02 02:13:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2173,6 +2173,7 @@ _copyRuleStmt(RuleStmt *from)
|
|||||||
Node_Copy(from, newnode, whereClause);
|
Node_Copy(from, newnode, whereClause);
|
||||||
newnode->event = from->event;
|
newnode->event = from->event;
|
||||||
newnode->instead = from->instead;
|
newnode->instead = from->instead;
|
||||||
|
newnode->replace = from->replace;
|
||||||
Node_Copy(from, newnode, actions);
|
Node_Copy(from, newnode, actions);
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
@ -2238,6 +2239,7 @@ _copyViewStmt(ViewStmt *from)
|
|||||||
Node_Copy(from, newnode, view);
|
Node_Copy(from, newnode, view);
|
||||||
Node_Copy(from, newnode, aliases);
|
Node_Copy(from, newnode, aliases);
|
||||||
Node_Copy(from, newnode, query);
|
Node_Copy(from, newnode, query);
|
||||||
|
newnode->replace = from->replace;
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.157 2002/08/31 22:10:43 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.158 2002/09/02 02:13:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1003,6 +1003,8 @@ _equalRuleStmt(RuleStmt *a, RuleStmt *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->instead != b->instead)
|
if (a->instead != b->instead)
|
||||||
return false;
|
return false;
|
||||||
|
if (a->replace != b->replace)
|
||||||
|
return false;
|
||||||
if (!equal(a->actions, b->actions))
|
if (!equal(a->actions, b->actions))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1067,6 +1069,8 @@ _equalViewStmt(ViewStmt *a, ViewStmt *b)
|
|||||||
return false;
|
return false;
|
||||||
if (!equal(a->query, b->query))
|
if (!equal(a->query, b->query))
|
||||||
return false;
|
return false;
|
||||||
|
if (a->replace != b->replace)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.364 2002/08/29 00:17:04 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.365 2002/09/02 02:13:01 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -3346,18 +3346,19 @@ opt_column: COLUMN { $$ = COLUMN; }
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
RuleStmt: CREATE RULE name AS
|
RuleStmt: CREATE opt_or_replace RULE name AS
|
||||||
{ QueryIsRule=TRUE; }
|
{ QueryIsRule=TRUE; }
|
||||||
ON event TO qualified_name where_clause
|
ON event TO qualified_name where_clause
|
||||||
DO opt_instead RuleActionList
|
DO opt_instead RuleActionList
|
||||||
{
|
{
|
||||||
RuleStmt *n = makeNode(RuleStmt);
|
RuleStmt *n = makeNode(RuleStmt);
|
||||||
n->relation = $9;
|
n->replace = $2;
|
||||||
n->rulename = $3;
|
n->relation = $10;
|
||||||
n->whereClause = $10;
|
n->rulename = $4;
|
||||||
n->event = $7;
|
n->whereClause = $11;
|
||||||
n->instead = $12;
|
n->event = $8;
|
||||||
n->actions = $13;
|
n->instead = $13;
|
||||||
|
n->actions = $14;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
QueryIsRule=FALSE;
|
QueryIsRule=FALSE;
|
||||||
}
|
}
|
||||||
@ -3537,12 +3538,14 @@ opt_trans: WORK {}
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
ViewStmt: CREATE VIEW qualified_name opt_column_list AS SelectStmt
|
ViewStmt: CREATE opt_or_replace VIEW qualified_name opt_column_list
|
||||||
|
AS SelectStmt
|
||||||
{
|
{
|
||||||
ViewStmt *n = makeNode(ViewStmt);
|
ViewStmt *n = makeNode(ViewStmt);
|
||||||
n->view = $3;
|
n->replace = $2;
|
||||||
n->aliases = $4;
|
n->view = $4;
|
||||||
n->query = (Query *) $6;
|
n->aliases = $5;
|
||||||
|
n->query = (Query *) $7;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.77 2002/08/05 03:29:17 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.78 2002/09/02 02:13:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -48,24 +48,23 @@ InsertRule(char *rulname,
|
|||||||
AttrNumber evslot_index,
|
AttrNumber evslot_index,
|
||||||
bool evinstead,
|
bool evinstead,
|
||||||
Node *event_qual,
|
Node *event_qual,
|
||||||
List *action)
|
List *action,
|
||||||
|
bool replace)
|
||||||
{
|
{
|
||||||
char *evqual = nodeToString(event_qual);
|
char *evqual = nodeToString(event_qual);
|
||||||
char *actiontree = nodeToString((Node *) action);
|
char *actiontree = nodeToString((Node *) action);
|
||||||
int i;
|
int i;
|
||||||
Datum values[Natts_pg_rewrite];
|
Datum values[Natts_pg_rewrite];
|
||||||
char nulls[Natts_pg_rewrite];
|
char nulls[Natts_pg_rewrite];
|
||||||
|
char replaces[Natts_pg_rewrite];
|
||||||
NameData rname;
|
NameData rname;
|
||||||
Relation pg_rewrite_desc;
|
Relation pg_rewrite_desc;
|
||||||
TupleDesc tupDesc;
|
HeapTuple tup,
|
||||||
HeapTuple tup;
|
oldtup;
|
||||||
Oid rewriteObjectId;
|
Oid rewriteObjectId;
|
||||||
ObjectAddress myself,
|
ObjectAddress myself,
|
||||||
referenced;
|
referenced;
|
||||||
|
bool is_update = false;
|
||||||
if (IsDefinedRewriteRule(eventrel_oid, rulname))
|
|
||||||
elog(ERROR, "Attempt to insert rule \"%s\" failed: already exists",
|
|
||||||
rulname);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up *nulls and *values arrays
|
* Set up *nulls and *values arrays
|
||||||
@ -83,22 +82,61 @@ InsertRule(char *rulname,
|
|||||||
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree)); /* ev_action */
|
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree)); /* ev_action */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new pg_rewrite tuple
|
* Ready to store new pg_rewrite tuple
|
||||||
*/
|
*/
|
||||||
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
|
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
tupDesc = pg_rewrite_desc->rd_att;
|
/*
|
||||||
|
* Check to see if we are replacing an existing tuple
|
||||||
|
*/
|
||||||
|
oldtup = SearchSysCache(RULERELNAME,
|
||||||
|
ObjectIdGetDatum(eventrel_oid),
|
||||||
|
PointerGetDatum(rulname),
|
||||||
|
0, 0);
|
||||||
|
|
||||||
tup = heap_formtuple(tupDesc,
|
if (HeapTupleIsValid(oldtup))
|
||||||
values,
|
{
|
||||||
nulls);
|
if (!replace)
|
||||||
|
elog(ERROR,"Attempt to insert rule \"%s\" failed: already exists",
|
||||||
|
rulname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When replacing, we don't need to replace every attribute
|
||||||
|
*/
|
||||||
|
MemSet(replaces, ' ', sizeof(replaces));
|
||||||
|
replaces[Anum_pg_rewrite_ev_attr - 1] = 'r';
|
||||||
|
replaces[Anum_pg_rewrite_ev_type - 1] = 'r';
|
||||||
|
replaces[Anum_pg_rewrite_is_instead - 1] = 'r';
|
||||||
|
replaces[Anum_pg_rewrite_ev_qual - 1] = 'r';
|
||||||
|
replaces[Anum_pg_rewrite_ev_action - 1] = 'r';
|
||||||
|
|
||||||
|
tup = heap_modifytuple(oldtup, pg_rewrite_desc,
|
||||||
|
values, nulls, replaces);
|
||||||
|
|
||||||
|
simple_heap_update(pg_rewrite_desc, &tup->t_self, tup);
|
||||||
|
|
||||||
|
ReleaseSysCache(oldtup);
|
||||||
|
|
||||||
|
rewriteObjectId = HeapTupleGetOid(tup);
|
||||||
|
is_update = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tup = heap_formtuple(pg_rewrite_desc->rd_att, values, nulls);
|
||||||
|
|
||||||
rewriteObjectId = simple_heap_insert(pg_rewrite_desc, tup);
|
rewriteObjectId = simple_heap_insert(pg_rewrite_desc, tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to update indexes in either case */
|
||||||
CatalogUpdateIndexes(pg_rewrite_desc, tup);
|
CatalogUpdateIndexes(pg_rewrite_desc, tup);
|
||||||
|
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
|
|
||||||
|
/* If replacing, get rid of old dependencies and make new ones */
|
||||||
|
if (is_update)
|
||||||
|
deleteDependencyRecordsFor(RelationGetRelid(pg_rewrite_desc),
|
||||||
|
rewriteObjectId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Install dependency on rule's relation to ensure it will go away
|
* Install dependency on rule's relation to ensure it will go away
|
||||||
* on relation deletion. If the rule is ON SELECT, make the dependency
|
* on relation deletion. If the rule is ON SELECT, make the dependency
|
||||||
@ -121,6 +159,7 @@ InsertRule(char *rulname,
|
|||||||
*/
|
*/
|
||||||
recordDependencyOnExpr(&myself, (Node *) action, NIL,
|
recordDependencyOnExpr(&myself, (Node *) action, NIL,
|
||||||
DEPENDENCY_NORMAL);
|
DEPENDENCY_NORMAL);
|
||||||
|
|
||||||
if (event_qual != NULL)
|
if (event_qual != NULL)
|
||||||
{
|
{
|
||||||
/* Find query containing OLD/NEW rtable entries */
|
/* Find query containing OLD/NEW rtable entries */
|
||||||
@ -143,6 +182,7 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
Node *event_qual = stmt->whereClause;
|
Node *event_qual = stmt->whereClause;
|
||||||
CmdType event_type = stmt->event;
|
CmdType event_type = stmt->event;
|
||||||
bool is_instead = stmt->instead;
|
bool is_instead = stmt->instead;
|
||||||
|
bool replace = stmt->replace;
|
||||||
List *action = stmt->actions;
|
List *action = stmt->actions;
|
||||||
Relation event_relation;
|
Relation event_relation;
|
||||||
Oid ev_relid;
|
Oid ev_relid;
|
||||||
@ -232,7 +272,7 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
* event relation, ...
|
* event relation, ...
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(tllist, query->targetList)
|
foreach (tllist, query->targetList)
|
||||||
{
|
{
|
||||||
TargetEntry *tle = (TargetEntry *) lfirst(tllist);
|
TargetEntry *tle = (TargetEntry *) lfirst(tllist);
|
||||||
Resdom *resdom = tle->resdom;
|
Resdom *resdom = tle->resdom;
|
||||||
@ -282,7 +322,7 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
/*
|
/*
|
||||||
* ... there must not be another ON SELECT rule already ...
|
* ... there must not be another ON SELECT rule already ...
|
||||||
*/
|
*/
|
||||||
if (event_relation->rd_rules != NULL)
|
if (!replace && event_relation->rd_rules != NULL)
|
||||||
{
|
{
|
||||||
for (i = 0; i < event_relation->rd_rules->numLocks; i++)
|
for (i = 0; i < event_relation->rd_rules->numLocks; i++)
|
||||||
{
|
{
|
||||||
@ -364,7 +404,8 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
event_attno,
|
event_attno,
|
||||||
is_instead,
|
is_instead,
|
||||||
event_qual,
|
event_qual,
|
||||||
action);
|
action,
|
||||||
|
replace);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set pg_class 'relhasrules' field TRUE for event relation. If
|
* Set pg_class 'relhasrules' field TRUE for event relation. If
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.175 2002/08/30 19:23:20 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.176 2002/09/02 02:13:01 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -595,7 +595,7 @@ ProcessUtility(Node *parsetree,
|
|||||||
{
|
{
|
||||||
ViewStmt *stmt = (ViewStmt *) parsetree;
|
ViewStmt *stmt = (ViewStmt *) parsetree;
|
||||||
|
|
||||||
DefineView(stmt->view, stmt->query);
|
DefineView(stmt->view, stmt->query, stmt->replace);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: view.h,v 1.16 2002/07/01 15:27:56 tgl Exp $
|
* $Id: view.h,v 1.17 2002/09/02 02:13:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
extern void DefineView(const RangeVar *view, Query *view_parse);
|
extern void DefineView(const RangeVar *view, Query *view_parse, bool replace);
|
||||||
extern void RemoveView(const RangeVar *view, DropBehavior behavior);
|
extern void RemoveView(const RangeVar *view, DropBehavior behavior);
|
||||||
|
|
||||||
#endif /* VIEW_H */
|
#endif /* VIEW_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.204 2002/08/31 22:10:47 tgl Exp $
|
* $Id: parsenodes.h,v 1.205 2002/09/02 02:13:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1371,6 +1371,7 @@ typedef struct RuleStmt
|
|||||||
CmdType event; /* SELECT, INSERT, etc */
|
CmdType event; /* SELECT, INSERT, etc */
|
||||||
bool instead; /* is a 'do instead'? */
|
bool instead; /* is a 'do instead'? */
|
||||||
List *actions; /* the action statements */
|
List *actions; /* the action statements */
|
||||||
|
bool replace; /* OR REPLACE */
|
||||||
} RuleStmt;
|
} RuleStmt;
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
@ -1436,6 +1437,7 @@ typedef struct ViewStmt
|
|||||||
RangeVar *view; /* the view to be created */
|
RangeVar *view; /* the view to be created */
|
||||||
List *aliases; /* target column names */
|
List *aliases; /* target column names */
|
||||||
Query *query; /* the SQL statement */
|
Query *query; /* the SQL statement */
|
||||||
|
bool replace; /* replace an existing view? */
|
||||||
} ViewStmt;
|
} ViewStmt;
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
|
@ -15,3 +15,43 @@ CREATE VIEW iexit AS
|
|||||||
CREATE VIEW toyemp AS
|
CREATE VIEW toyemp AS
|
||||||
SELECT name, age, location, 12*salary AS annualsal
|
SELECT name, age, location, 12*salary AS annualsal
|
||||||
FROM emp;
|
FROM emp;
|
||||||
|
--
|
||||||
|
-- CREATE OR REPLACE VIEW
|
||||||
|
--
|
||||||
|
CREATE TABLE viewtest_tbl (a int, b int);
|
||||||
|
COPY viewtest_tbl FROM stdin;
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT * FROM viewtest_tbl;
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT * FROM viewtest_tbl WHERE a > 10;
|
||||||
|
SELECT * FROM viewtest;
|
||||||
|
a | b
|
||||||
|
----+----
|
||||||
|
15 | 20
|
||||||
|
20 | 25
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a, b FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
|
||||||
|
SELECT * FROM viewtest;
|
||||||
|
a | b
|
||||||
|
----+----
|
||||||
|
20 | 25
|
||||||
|
15 | 20
|
||||||
|
10 | 15
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a FROM viewtest_tbl WHERE a <> 20;
|
||||||
|
ERROR: Cannot change column set of existing view viewtest
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT 1, * FROM viewtest_tbl;
|
||||||
|
ERROR: Cannot change column set of existing view viewtest
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a, b::numeric FROM viewtest_tbl;
|
||||||
|
ERROR: Cannot change column set of existing view viewtest
|
||||||
|
DROP VIEW viewtest;
|
||||||
|
DROP TABLE viewtest_tbl;
|
||||||
|
@ -1343,3 +1343,21 @@ SELECT tablename, rulename, definition FROM pg_rules
|
|||||||
shoelace_ok | shoelace_ok_ins | CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok DO INSTEAD UPDATE shoelace SET sl_avail = (shoelace.sl_avail + new.ok_quant) WHERE (shoelace.sl_name = new.ok_name);
|
shoelace_ok | shoelace_ok_ins | CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok DO INSTEAD UPDATE shoelace SET sl_avail = (shoelace.sl_avail + new.ok_quant) WHERE (shoelace.sl_name = new.ok_name);
|
||||||
(29 rows)
|
(29 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- CREATE OR REPLACE RULE
|
||||||
|
--
|
||||||
|
CREATE TABLE ruletest_tbl (a int, b int);
|
||||||
|
CREATE TABLE ruletest_tbl2 (a int, b int);
|
||||||
|
CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
|
||||||
|
DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (10, 10);
|
||||||
|
INSERT INTO ruletest_tbl VALUES (99, 99);
|
||||||
|
CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
|
||||||
|
DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (1000, 1000);
|
||||||
|
INSERT INTO ruletest_tbl VALUES (99, 99);
|
||||||
|
SELECT * FROM ruletest_tbl2;
|
||||||
|
a | b
|
||||||
|
------+------
|
||||||
|
10 | 10
|
||||||
|
1000 | 1000
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
@ -19,3 +19,42 @@ CREATE VIEW toyemp AS
|
|||||||
SELECT name, age, location, 12*salary AS annualsal
|
SELECT name, age, location, 12*salary AS annualsal
|
||||||
FROM emp;
|
FROM emp;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- CREATE OR REPLACE VIEW
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE viewtest_tbl (a int, b int);
|
||||||
|
COPY viewtest_tbl FROM stdin;
|
||||||
|
5 10
|
||||||
|
10 15
|
||||||
|
15 20
|
||||||
|
20 25
|
||||||
|
\.
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT * FROM viewtest_tbl;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT * FROM viewtest_tbl WHERE a > 10;
|
||||||
|
|
||||||
|
SELECT * FROM viewtest;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a, b FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
|
||||||
|
|
||||||
|
SELECT * FROM viewtest;
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a FROM viewtest_tbl WHERE a <> 20;
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT 1, * FROM viewtest_tbl;
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
CREATE OR REPLACE VIEW viewtest AS
|
||||||
|
SELECT a, b::numeric FROM viewtest_tbl;
|
||||||
|
|
||||||
|
DROP VIEW viewtest;
|
||||||
|
DROP TABLE viewtest_tbl;
|
||||||
|
@ -765,3 +765,21 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname;
|
|||||||
SELECT tablename, rulename, definition FROM pg_rules
|
SELECT tablename, rulename, definition FROM pg_rules
|
||||||
ORDER BY tablename, rulename;
|
ORDER BY tablename, rulename;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- CREATE OR REPLACE RULE
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE ruletest_tbl (a int, b int);
|
||||||
|
CREATE TABLE ruletest_tbl2 (a int, b int);
|
||||||
|
|
||||||
|
CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
|
||||||
|
DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (10, 10);
|
||||||
|
|
||||||
|
INSERT INTO ruletest_tbl VALUES (99, 99);
|
||||||
|
|
||||||
|
CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
|
||||||
|
DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (1000, 1000);
|
||||||
|
|
||||||
|
INSERT INTO ruletest_tbl VALUES (99, 99);
|
||||||
|
|
||||||
|
SELECT * FROM ruletest_tbl2;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user