OSDN Git Service

CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Sep 2002 02:13:02 +0000 (02:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Sep 2002 02:13:02 +0000 (02:13 +0000)
Gavin Sherry, Neil Conway, and Tom Lane all got their hands dirty
on this one ...

12 files changed:
src/backend/commands/view.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/rewrite/rewriteDefine.c
src/backend/tcop/utility.c
src/include/commands/view.h
src/include/nodes/parsenodes.h
src/test/regress/expected/create_view.out
src/test/regress/expected/rules.out
src/test/regress/sql/create_view.sql
src/test/regress/sql/rules.sql

index c635a28..46cdf0a 100644 (file)
@@ -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);
 }
 
 /*
index 1938e7f..8a69af3 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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);
        newnode->event = from->event;
        newnode->instead = from->instead;
+       newnode->replace = from->replace;
        Node_Copy(from, newnode, actions);
 
        return newnode;
@@ -2238,6 +2239,7 @@ _copyViewStmt(ViewStmt *from)
        Node_Copy(from, newnode, view);
        Node_Copy(from, newnode, aliases);
        Node_Copy(from, newnode, query);
+       newnode->replace = from->replace;
 
        return newnode;
 }
index 10b8e79..7f677c0 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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;
        if (a->instead != b->instead)
                return false;
+       if (a->replace != b->replace)
+               return false;
        if (!equal(a->actions, b->actions))
                return false;
 
@@ -1067,6 +1069,8 @@ _equalViewStmt(ViewStmt *a, ViewStmt *b)
                return false;
        if (!equal(a->query, b->query))
                return false;
+       if (a->replace != b->replace)
+               return false;
 
        return true;
 }
index 463a8d5..674a6d0 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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
  *       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; }
                        ON event TO qualified_name where_clause
                        DO opt_instead RuleActionList
                                {
                                        RuleStmt *n = makeNode(RuleStmt);
-                                       n->relation = $9;
-                                       n->rulename = $3;
-                                       n->whereClause = $10;
-                                       n->event = $7;
-                                       n->instead = $12;
-                                       n->actions = $13;
+                                       n->replace = $2;
+                                       n->relation = $10;
+                                       n->rulename = $4;
+                                       n->whereClause = $11;
+                                       n->event = $8;
+                                       n->instead = $13;
+                                       n->actions = $14;
                                        $$ = (Node *)n;
                                        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);
-                                       n->view = $3;
-                                       n->aliases = $4;
-                                       n->query = (Query *) $6;
+                                       n->replace = $2;
+                                       n->view = $4;
+                                       n->aliases = $5;
+                                       n->query = (Query *) $7;
                                        $$ = (Node *)n;
                                }
                ;
index 80952d7..f276189 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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,
                   bool evinstead,
                   Node *event_qual,
-                  List *action)
+                  List *action,
+                  bool replace)
 {
        char       *evqual = nodeToString(event_qual);
        char       *actiontree = nodeToString((Node *) action);
        int                     i;
        Datum           values[Natts_pg_rewrite];
        char            nulls[Natts_pg_rewrite];
+       char            replaces[Natts_pg_rewrite];
        NameData        rname;
        Relation        pg_rewrite_desc;
-       TupleDesc       tupDesc;
-       HeapTuple       tup;
+       HeapTuple       tup,
+                               oldtup;
        Oid                     rewriteObjectId;
        ObjectAddress   myself,
                                        referenced;
-
-       if (IsDefinedRewriteRule(eventrel_oid, rulname))
-               elog(ERROR, "Attempt to insert rule \"%s\" failed: already exists",
-                        rulname);
+       bool            is_update = false;
 
        /*
         * Set up *nulls and *values arrays
@@ -83,22 +82,61 @@ InsertRule(char *rulname,
        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);
 
-       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,
-                                                values,
-                                                nulls);
+               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);
 
        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
         * on relation deletion.  If the rule is ON SELECT, make the dependency
@@ -114,13 +152,14 @@ InsertRule(char *rulname,
        referenced.objectSubId = 0;
 
        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.
         */
        recordDependencyOnExpr(&myself, (Node *) action, NIL,
                                                   DEPENDENCY_NORMAL);
+
        if (event_qual != NULL)
        {
                /* Find query containing OLD/NEW rtable entries */
@@ -143,6 +182,7 @@ DefineQueryRewrite(RuleStmt *stmt)
        Node       *event_qual = stmt->whereClause;
        CmdType         event_type = stmt->event;
        bool            is_instead = stmt->instead;
+       bool            replace = stmt->replace;
        List       *action = stmt->actions;
        Relation        event_relation;
        Oid                     ev_relid;
@@ -232,7 +272,7 @@ DefineQueryRewrite(RuleStmt *stmt)
                 * event relation, ...
                 */
                i = 0;
-               foreach(tllist, query->targetList)
+               foreach (tllist, query->targetList)
                {
                        TargetEntry *tle = (TargetEntry *) lfirst(tllist);
                        Resdom     *resdom = tle->resdom;
@@ -282,7 +322,7 @@ DefineQueryRewrite(RuleStmt *stmt)
                /*
                 * ... 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++)
                        {
@@ -364,7 +404,8 @@ DefineQueryRewrite(RuleStmt *stmt)
                                                        event_attno,
                                                        is_instead,
                                                        event_qual,
-                                                       action);
+                                                       action,
+                                                       replace);
 
                /*
                 * Set pg_class 'relhasrules' field TRUE for event relation. If
index 17a2533..40dec9d 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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;
 
-                               DefineView(stmt->view, stmt->query);
+                               DefineView(stmt->view, stmt->query, stmt->replace);
                        }
                        break;
 
index 3603f2a..e476d82 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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"
 
-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);
 
 #endif   /* VIEW_H */
index a426aeb..be8b7fe 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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 */
        bool            instead;                /* is a 'do instead'? */
        List       *actions;            /* the action statements */
+       bool            replace;                /* OR REPLACE */
 } RuleStmt;
 
 /* ----------------------
@@ -1436,6 +1437,7 @@ typedef struct ViewStmt
        RangeVar   *view;                       /* the view to be created */
        List       *aliases;            /* target column names */
        Query      *query;                      /* the SQL statement */
+       bool            replace;                /* replace an existing view? */
 } ViewStmt;
 
 /* ----------------------
index e398440..ade98e6 100644 (file)
@@ -15,3 +15,43 @@ CREATE VIEW iexit AS
 CREATE VIEW toyemp AS
    SELECT name, age, location, 12*salary AS annualsal
    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;
index 0cfd3f1..bcce233 100644 (file)
@@ -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);
 (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)
+
index 858c8ce..8c15fc1 100644 (file)
@@ -19,3 +19,42 @@ CREATE VIEW toyemp AS
    SELECT name, age, location, 12*salary AS annualsal
    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;
index 6ee6f2a..20afc9f 100644 (file)
@@ -765,3 +765,21 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname;
 SELECT tablename, rulename, definition FROM pg_rules 
        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;