Commit 248c67d7 authored by Tom Lane's avatar Tom Lane

CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE.

Gavin Sherry, Neil Conway, and Tom Lane all got their hands dirty
on this one ...
parent c7a165ad
...@@ -6,43 +6,43 @@ ...@@ -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) ...@@ -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;
...@@ -83,23 +83,74 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist) ...@@ -83,23 +83,74 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist)
elog(ERROR, "attempted to define virtual relation with no attrs"); elog(ERROR, "attempted to define virtual relation with no attrs");
/* /*
* now create the parameters for keys/inheritance etc. All of them are * Check to see if we want to replace an existing view.
* nil...
*/ */
createStmt->relation = (RangeVar *) relation; namespaceId = RangeVarGetCreationNamespace(relation);
createStmt->tableElts = attrList; viewOid = get_relname_relid(relation->relname, namespaceId);
createStmt->inhRelations = NIL;
createStmt->constraints = NIL;
createStmt->hasoids = false;
/* if (OidIsValid(viewOid) && replace)
* finally create the relation... {
*/ Relation rel;
return DefineRelation(createStmt, RELKIND_VIEW); 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 * 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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; } ...@@ -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 {} ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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);
if (HeapTupleIsValid(oldtup))
{
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);
tup = heap_formtuple(tupDesc, ReleaseSysCache(oldtup);
values,
nulls); 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
...@@ -114,13 +152,14 @@ InsertRule(char *rulname, ...@@ -114,13 +152,14 @@ InsertRule(char *rulname,
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, recordDependencyOn(&myself, &referenced,
(evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
/* /*
* Also install dependencies on objects referenced in action and qual. * Also install dependencies on objects referenced in action and qual.
*/ */
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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; ...@@ -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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment