diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4fae50cd32..53d8142b78 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-
+
@@ -4154,13 +4154,6 @@
True if the rule is an INSTEAD rule
-
- is_auto
- bool
-
- True if the rule was automatically generated
-
-
ev_qual
text
diff --git a/doc/src/sgml/intro.sgml b/doc/src/sgml/intro.sgml
index 298ba910a9..ccc3c8d772 100644
--- a/doc/src/sgml/intro.sgml
+++ b/doc/src/sgml/intro.sgml
@@ -1,4 +1,4 @@
-
+
Preface
@@ -110,7 +110,7 @@
triggers
- updatable views
+ views
transactional integrity
diff --git a/doc/src/sgml/ref/create_view.sgml b/doc/src/sgml/ref/create_view.sgml
index daea5a97cb..1a3281dda6 100644
--- a/doc/src/sgml/ref/create_view.sgml
+++ b/doc/src/sgml/ref/create_view.sgml
@@ -1,5 +1,5 @@
@@ -115,99 +115,11 @@ CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] VIEW n
Notes
- Some views are updatable, which means that the
- commands INSERT, UPDATE,
- and DELETE can be used on the view as if it
- were a regular table. A view is updatable if it
- does not contain:
-
-
-
-
- more than one underlying table (joins) or no underlying table at all
-
-
-
-
-
- underlying tables/views that are themselves not updatable,
- including table value constructors and table functions
-
-
-
-
-
- subqueries in the FROM list
-
-
-
-
-
- items in the select list that are not direct references to a
- column of the underlying table, such as literals or any
- nontrivial value expression
-
-
-
-
-
- references to system columns in the select list
-
-
-
-
-
- more than one reference to the same column in the select list
-
-
-
-
- aggregate function calls
-
-
-
- window function calls
-
-
-
-
- WITH or WITH RECURSIVE clauses
-
-
-
-
-
- DISTINCT, GROUP BY, or
- HAVING clauses
-
-
-
-
-
- UNION, INTERSECT, or
- EXCEPT clauses
-
-
-
-
-
- LIMIT or OFFSET clauses
- (or other equivalent spellings thereof)
-
-
-
-
-
-
- The updatable views implementation is based on the rule system.
- Because of this, you can also make more complex views updatable or
- insertable by creating your own rules that rewrite
- the INSERT,
- UPDATE, and DELETE actions
- on the view into appropriate actions on other tables. You can
- also replace the automatically generated rules by your own rules.
- For more information on the rule system, refer
- to .
+ Currently, views are read only: the system will not allow an insert,
+ update, or delete on a view. You can get the effect of an updatable
+ view by creating rules that rewrite inserts, etc. on the view into
+ appropriate actions on other tables. For more information see
+ .
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index de1834ab1c..909c6a8865 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.112 2009/01/22 17:27:54 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.113 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,9 +27,7 @@
#include "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
-#include "rewrite/rewriteRemove.h"
#include "rewrite/rewriteSupport.h"
-#include "rewrite/viewUpdate.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -310,28 +308,13 @@ DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
viewOid,
NULL,
CMD_SELECT,
- true, /* is_instead */
- true, /* is_auto */
+ true,
replace,
list_make1(viewParse));
/*
- * Delete all implicit rules on replace. CreateViewUpdateRules()
- * below will re-create them if appropriate for the new view
- * definition.
+ * Someday: automatic ON INSERT, etc
*/
- if (replace)
- {
- Relation rel = heap_open(viewOid, AccessExclusiveLock);
- RemoveAutomaticRulesOnEvent(rel, CMD_INSERT);
- RemoveAutomaticRulesOnEvent(rel, CMD_DELETE);
- RemoveAutomaticRulesOnEvent(rel, CMD_UPDATE);
- heap_close(rel, NoLock);
- }
-
- CommandCounterIncrement();
-
- CreateViewUpdateRules(viewOid, viewParse);
}
/*---------------------------------------------------------------
diff --git a/src/backend/rewrite/Makefile b/src/backend/rewrite/Makefile
index 196765aa6c..c4c64cb0cc 100644
--- a/src/backend/rewrite/Makefile
+++ b/src/backend/rewrite/Makefile
@@ -4,7 +4,7 @@
# Makefile for rewrite
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/rewrite/Makefile,v 1.18 2009/01/22 17:27:54 petere Exp $
+# $PostgreSQL: pgsql/src/backend/rewrite/Makefile,v 1.19 2009/01/27 12:40:15 petere Exp $
#
#-------------------------------------------------------------------------
@@ -13,7 +13,6 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = rewriteRemove.o rewriteDefine.o \
- rewriteHandler.o rewriteManip.o rewriteSupport.o \
- viewUpdate.o
+ rewriteHandler.o rewriteManip.o rewriteSupport.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index fe81a9ff13..03c5c5ae38 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,14 +8,13 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.135 2009/01/22 17:27:54 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.136 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
-#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
@@ -26,7 +25,6 @@
#include "parser/parse_utilcmd.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
-#include "rewrite/rewriteRemove.h"
#include "rewrite/rewriteSupport.h"
#include "utils/acl.h"
#include "utils/builtins.h"
@@ -41,7 +39,6 @@ static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
bool isSelect);
static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
static void setRuleCheckAsUser_Query(Query *qry, Oid userid);
-static const char *rule_event_string(CmdType evtype);
/*
@@ -55,7 +52,6 @@ InsertRule(char *rulname,
Oid eventrel_oid,
AttrNumber evslot_index,
bool evinstead,
- bool is_auto,
Node *event_qual,
List *action,
bool replace)
@@ -88,7 +84,6 @@ InsertRule(char *rulname,
values[i++] = CharGetDatum(evtype + '0'); /* ev_type */
values[i++] = CharGetDatum(RULE_FIRES_ON_ORIGIN); /* ev_enabled */
values[i++] = BoolGetDatum(evinstead); /* is_instead */
- values[i++] = BoolGetDatum(is_auto); /* is_auto */
values[i++] = CStringGetTextDatum(evqual); /* ev_qual */
values[i++] = CStringGetTextDatum(actiontree); /* ev_action */
@@ -107,11 +102,7 @@ InsertRule(char *rulname,
if (HeapTupleIsValid(oldtup))
{
- /*
- * If REPLACE was not used we still check if the old rule is
- * automatic: Then we replace it anyway.
- */
- if (!replace && !((Form_pg_rewrite) GETSTRUCT(oldtup))->is_auto)
+ if (!replace)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("rule \"%s\" for relation \"%s\" already exists",
@@ -124,7 +115,6 @@ InsertRule(char *rulname,
replaces[Anum_pg_rewrite_ev_attr - 1] = true;
replaces[Anum_pg_rewrite_ev_type - 1] = true;
replaces[Anum_pg_rewrite_is_instead - 1] = true;
- replaces[Anum_pg_rewrite_is_auto - 1] = true;
replaces[Anum_pg_rewrite_ev_qual - 1] = true;
replaces[Anum_pg_rewrite_ev_action - 1] = true;
@@ -215,7 +205,6 @@ DefineRule(RuleStmt *stmt, const char *queryString)
whereClause,
stmt->event,
stmt->instead,
- false, /* not is_auto */
stmt->replace,
actions);
}
@@ -234,7 +223,6 @@ DefineQueryRewrite(char *rulename,
Node *event_qual,
CmdType event_type,
bool is_instead,
- bool is_auto,
bool replace,
List *action)
{
@@ -458,42 +446,6 @@ DefineQueryRewrite(char *rulename,
RelationGetDescr(event_relation),
false);
}
-
- /*
- * If defining a non-automatic DO INSTEAD rule, drop all
- * automatic rules on the same event.
- */
- if (!is_auto && is_instead)
- {
- RemoveAutomaticRulesOnEvent(event_relation, event_type);
- CommandCounterIncrement();
- }
-
- /*
- * If defining an automatic rule and there is a manual rule on
- * the same event, warn and don't do it.
- */
- if (is_auto && event_relation->rd_rules != NULL)
- {
- int i;
-
- for (i = 0; i < event_relation->rd_rules->numLocks; i++)
- {
- RewriteRule *rule = event_relation->rd_rules->rules[i];
-
- if (rule->event == event_type && !rule->is_auto && rule->isInstead == is_instead)
- {
- ereport(WARNING,
- (errmsg("automatic %s rule not created because manually created %s rule exists",
- rule_event_string(event_type), rule_event_string(event_type)),
- errhint("If you prefer to have the automatic rule, drop the manually created rule and run CREATE OR REPLACE VIEW again.")));
-
- heap_close(event_relation, NoLock);
- return;
- }
- }
- }
-
}
/*
@@ -509,7 +461,6 @@ DefineQueryRewrite(char *rulename,
event_relid,
event_attno,
is_instead,
- is_auto,
event_qual,
action,
replace);
@@ -803,16 +754,3 @@ RenameRewriteRule(Oid owningRel, const char *oldName,
}
#endif
-
-
-static const char *
-rule_event_string(CmdType type)
-{
- if (type == CMD_INSERT)
- return "INSERT";
- if (type == CMD_UPDATE)
- return "UPDATE";
- if (type == CMD_DELETE)
- return "DELETE";
- return "???";
-}
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 7cfeacb730..336ae829ce 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.184 2009/01/22 20:16:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.185 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1899,20 +1899,20 @@ QueryRewrite(Query *parsetree)
{
case CMD_INSERT:
ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("view is not updatable"),
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot insert into a view"),
errhint("You need an unconditional ON INSERT DO INSTEAD rule.")));
break;
case CMD_UPDATE:
ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("view is not updatable"),
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot update a view"),
errhint("You need an unconditional ON UPDATE DO INSTEAD rule.")));
break;
case CMD_DELETE:
ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("view is not updatable"),
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot delete from a view"),
errhint("You need an unconditional ON DELETE DO INSTEAD rule.")));
break;
default:
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index 90e99bd8ac..a7b4413e3e 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.76 2009/01/22 17:27:54 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.77 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -90,39 +90,6 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior,
performDeletion(&object, behavior);
}
-/*
- * RemoveAutomaticRulesOnEvent
- *
- * This will delete automatic rules, if any exist, on the event in the
- * relation.
- */
-void
-RemoveAutomaticRulesOnEvent(Relation rel, CmdType event_type)
-{
- RuleLock *rulelocks = rel->rd_rules;
- int i;
-
- /* If there are no rules on the relation, waste no more time. */
- if (rulelocks == NULL)
- return;
-
- /*
- * Look at all rules looking for the ones that are on the event
- * and are automatic.
- */
- for (i = 0; i < rulelocks->numLocks; i++)
- {
- RewriteRule *oneLock = rulelocks->rules[i];
-
- if (oneLock->event == event_type && oneLock->is_auto)
- {
- RemoveRewriteRuleById(oneLock->ruleId);
- elog(DEBUG1, "removing automatic rule with OID %u\n",
- oneLock->ruleId);
- deleteDependencyRecordsFor(RewriteRelationId, oneLock->ruleId);
- }
- }
-}
/*
* Guts of rule deletion.
diff --git a/src/backend/rewrite/viewUpdate.c b/src/backend/rewrite/viewUpdate.c
deleted file mode 100644
index 3687f19429..0000000000
--- a/src/backend/rewrite/viewUpdate.c
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * viewUpdate.c
- * routines for translating a view definition into
- * INSERT/UPDATE/DELETE rules (i.e. updatable views).
- *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * ORIGINAL AUTHORS
- * Bernd Helmle, Jaime Casanova
- *
- * IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/viewUpdate.c,v 1.1 2009/01/22 17:27:54 petere Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/heapam.h"
-#include "access/xact.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_rewrite.h"
-#include "nodes/nodeFuncs.h"
-#include "parser/parse_oper.h"
-#include "parser/parsetree.h"
-#include "rewrite/rewriteDefine.h"
-#include "rewrite/viewUpdate.h"
-#include "utils/lsyscache.h"
-#include "utils/memutils.h"
-#include "utils/syscache.h"
-#include "utils/rel.h"
-
-typedef TargetEntry** ViewDefColumnList;
-
-typedef struct ViewBaseRelation
-{
- List *defs; /* List of all base relations (root starts
- * with only one relation because we
- * implement only simple updatability) */
- Oid parentRelation; /* Oid of parent relation, 0 indicates root */
-} ViewBaseRelation;
-
-typedef struct ViewBaseRelationItem
-{
- Relation rel; /* the Relation itself */
- Query *rule; /* _RETURN rule of a view relation */
- TargetEntry **tentries; /* saves order of column target list */
-} ViewBaseRelationItem;
-
-typedef struct ViewExprContext
-{
- Index newRTE;
- Index oldRTE;
- Index baseRTE;
- Index subQueryLevel;
- ViewDefColumnList tentries;
-} ViewExprContext;
-
-static const char *get_auto_rule_name(CmdType type);
-static Query *get_return_rule(Relation rel);
-static void read_rearranged_cols(ViewBaseRelation *tree);
-static bool is_select_query_updatable(const Query *query);
-static Oid get_reloid_from_select(const Query *select,
- int *rti, RangeTblEntry **rel_entry);
-static void create_update_rule(Oid viewOid,
- const Query *select,
- const Relation baserel,
- TargetEntry **tentries,
- CmdType ruletype);
-static void get_base_base_relations(const Query *view, Oid baserelid, List **list);
-static void copyReversedTargetEntryPtr(List *targetList,
- ViewDefColumnList targets);
-static bool check_reltree(ViewBaseRelation *node);
-static Query *form_update_query(const Query *select, ViewDefColumnList tentries, CmdType type);
-static RangeTblEntry *get_relation_RTE(const Query *select,
- unsigned int *offset);
-static Index get_rtindex_for_rel(List *rte_list,
- const char *relname);
-static bool replace_tlist_varno_walker(Node *node,
- ViewExprContext *ctxt);
-static OpExpr *create_opexpr(Var *var_left, Var *var_right);
-static void form_where_for_updrule(const Query *select, FromExpr **from,
- const Relation baserel, Index baserti,
- Index oldrti);
-static void build_update_target_list(const Query *update, const Query *select,
- const Relation baserel);
-
-/*------------------------------------------------------------------------------
- * Private functions
- * -----------------------------------------------------------------------------
- */
-
-static const char *
-get_auto_rule_name(CmdType type)
-{
- if (type == CMD_INSERT)
- return "_INSERT";
- if (type == CMD_UPDATE)
- return "_UPDATE";
- if (type == CMD_DELETE)
- return "_DELETE";
- return NULL;
-}
-
-/*
- * Returns the range table index for the specified relname.
- *
- * XXX This seems pretty grotty ... can't we do this in some other way?
- */
-static Index
-get_rtindex_for_rel(List *rte_list, const char *relname)
-{
- ListCell *cell;
- int index = 0;
-
- AssertArg(relname);
-
- foreach(cell, rte_list)
- {
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(cell);
-
- index++;
-
- if (rte && strncmp(rte->eref->aliasname, relname, NAMEDATALEN) == 0)
- break;
- }
-
- Assert(index > 0);
-
- return (Index) index;
-}
-
-/*
- * Returns the RangeTblEntry starting at the specified offset. The
- * function can be used to iterate over the rtable list of the
- * specified select query tree. Returns NULL if nothing is found.
- *
- * NOTE: The function only returns those RangeTblEntry that do not
- * match a *NEW* or *OLD* RangeTblEntry.
- *
- * The offset is incremented as a side effect.
- */
-static RangeTblEntry *
-get_relation_RTE(const Query *select, unsigned int *offset)
-{
- AssertArg(offset);
- AssertArg(select);
-
- while (*offset <= list_length(select->rtable))
- {
- RangeTblEntry *rte = rt_fetch(*offset, select->rtable);
- (*offset)++;
-
- /* skip non-table RTEs */
- if (rte->rtekind != RTE_RELATION)
- continue;
-
- /*
- * Skip RTEs named *NEW* and *OLD*.
- *
- * XXX It would be nice to be able to use something else than just
- * the names here ... However, rtekind does not work as expected :-(
- */
- if (strncmp(rte->eref->aliasname, "*NEW*", 6) == 0
- || strncmp(rte->eref->aliasname, "*OLD*", 6) == 0)
- continue;
-
- return rte;
- }
-
- return NULL;
-}
-
-/*
- * Rewrite varno's and varattno for the specified Var node if it is in
- * a reversed order regarding to the underlying relation. The lookup
- * table tentries holds all TargetEntries which are on a different
- * location in the view definition. If var isn't on a different
- * position in the current view than on its original relation, nothing
- * is done.
- *
- * Note: This function assumes that the caller has already checked all
- * parameters for NULL.
- */
-static void
-adjustVarnoIfReversedCol(Var *var,
- Index newRTE,
- ViewDefColumnList tentries)
-{
- TargetEntry *entry = tentries[var->varattno - 1];
-
- /*
- * tentries holds NULL if given var isn't on a different location
- * in the view Only replace if column order is reversed.
- */
- if (entry && entry->resno != var->varattno)
- {
- var->varattno = entry->resno;
- var->varoattno = entry->resno;
- }
-
- /* Finally, make varno point to the *NEW* range table entry. */
- var->varno = newRTE;
- var->varnoold = newRTE;
-}
-
-/*
- * Creates an equal operator expression for the specified Vars. They
- * are assumed to be of the same type.
- */
-static OpExpr *
-create_opexpr(Var *var_left, Var *var_right)
-{
- OpExpr *result;
- HeapTuple tuple;
- Form_pg_operator operator;
- Oid eqOid;
-
- AssertArg(var_left);
- AssertArg(var_right);
- Assert(var_left->vartype == var_right->vartype);
-
- get_sort_group_operators(var_left->vartype, false, true, false,
- NULL, &eqOid, NULL);
-
- tuple = SearchSysCache(OPEROID, ObjectIdGetDatum(eqOid), 0, 0, 0);
-
- operator = (Form_pg_operator) GETSTRUCT(tuple);
- result = makeNode(OpExpr);
-
- result->opno = HeapTupleGetOid(tuple);
- result->opfuncid = operator->oprcode;
- result->opresulttype = operator->oprresult;
- result->opretset = false;
-
- result->args = lappend(result->args, var_left);
- result->args = lappend(result->args, var_right);
-
- ReleaseSysCache(tuple);
-
- return result;
-}
-
-/*
- * Creates an expression tree for a WHERE clause.
- *
- * If from is not NULL, assigns the root node to the specified
- * FromExpr of the target query tree.
- *
- * Note that the function appends the specified opExpr op to the
- * specified anchor (if anchor != NULL) and returns that immediately.
- * That way this function could be used to add operator nodes to an
- * existing BoolExpr tree or (if from is given), to create a new Query
- * qualification list.
- */
-static Node *
-build_expression_tree(FromExpr *from, Node **anchor, BoolExpr *expr, OpExpr *op)
-{
- /* Already some nodes there? */
- if (*anchor)
- {
- expr->args = lappend(expr->args, op);
- ((BoolExpr *)(*anchor))->args = lappend(((BoolExpr *)(*anchor))->args,
- expr);
- *anchor = (Node *)expr;
- }
- else
- {
- /* Currently no nodes ... */
- BoolExpr *boolexpr = makeNode(BoolExpr);
- expr->args = lappend(expr->args, op);
- boolexpr->args = lappend(boolexpr->args, expr);
-
- *anchor = (Node *) boolexpr;
-
- if (from)
- from->quals = *anchor;
- }
-
- return *anchor;
-}
-
-/*
- * Forms the WHERE clause for DELETE/UPDATE rules targeted to the
- * specified view.
- */
-static void
-form_where_for_updrule(const Query *select, /* View retrieve rule */
- FromExpr **from, /* FromExpr for stmt */
- const Relation baserel, /* base relation of view */
- Index baserti, /* Index of base relation RTE */
- Index oldrti) /* Index of *OLD* RTE */
-{
- BoolExpr *expr = NULL;
- Node *anchor = NULL;
- Form_pg_attribute *attrs;
- ListCell *cell;
-
- AssertArg(baserti > 0);
- AssertArg(oldrti > 0);
- AssertArg(*from);
- AssertArg(baserel);
-
- attrs = baserel->rd_att->attrs;
-
- foreach(cell, select->targetList)
- {
- TargetEntry *te = (TargetEntry *) lfirst(cell);
- Var *var1;
- Var *var2;
- OpExpr *op;
- BoolExpr *null_condition;
- NullTest *nulltest1;
- NullTest *nulltest2;
-
- /* If te->expr holds no Var pointer, continue. */
- if (!IsA(te->expr, Var))
- continue;
-
- null_condition = makeNode(BoolExpr);
- nulltest1 = makeNode(NullTest);
- nulltest2 = makeNode(NullTest);
-
- /*
- * These are the new operands we had to check for equality.
- *
- * For DELETE/UPDATE rules, var1 points to the *OLD* RTE, var2
- * references the base relation.
- */
- var1 = copyObject((Var *) (te->expr));
-
- /*
- * Look at varoattno to determine whether this attribute has a different
- * location in the underlying base table. If that case, retrieve the
- * attribute from the base table and assign it to var2; otherwise
- * simply copy it to var1.
- */
- if (var1->varoattno > 0)
- {
- var2 = makeNode(Var);
-
- var2->varno = baserti;
- var2->varnoold = baserti;
- var2->varattno = attrs[var1->varoattno - 1]->attnum;
- var2->vartype = attrs[var1->varoattno - 1]->atttypid;
- var2->vartypmod = attrs[var1->varoattno - 1]->atttypmod;
- var2->varlevelsup = var1->varlevelsup;
- var2->varnoold = var2->varno;
- var2->varoattno = var2->varattno;
- }
- else
- {
- var2 = copyObject(var1);
- var2->varno = baserti;
- var2->varnoold = baserti;
- }
-
- var1->varno = oldrti;
- var1->varnoold = oldrti;
-
- /*
- * rewrite varattno of var2 to point to the right column in relation
- * *OLD* or *NEW*
- */
- var2->varattno = te->resorigcol;
- var2->varoattno = te->resorigcol;
-
- /*
- * rewrite varattno of var1 to point to the right column in base
- * relation
- */
- var1->varattno = te->resno;
- var1->varoattno = te->resno;
-
- op = create_opexpr(var1, var2);
- expr = makeNode(BoolExpr);
- expr->boolop = OR_EXPR;
- null_condition->boolop = AND_EXPR;
-
- nulltest1->arg = (Expr *)var1;
- nulltest1->nulltesttype = IS_NULL;
-
- nulltest2->arg = (Expr *)var2;
- nulltest2->nulltesttype = IS_NULL;
-
- null_condition->args = lappend(null_condition->args, nulltest1);
- null_condition->args = lappend(null_condition->args, nulltest2);
- expr->args = lappend(expr->args, null_condition);
-
- anchor = build_expression_tree(*from, (Node **) &anchor, expr, op);
- }
-}
-
-/*
- * Replaces the varnos for the specified targetlist to rtIndex
- */
-static bool
-replace_tlist_varno_walker(Node *node,
- ViewExprContext *ctxt)
-{
- AssertArg(ctxt);
-
- if (!node)
- return false;
-
- switch(node->type)
- {
- case T_Var:
- elog(DEBUG1, "adjusting varno old %d to new %d",
- ((Var *)(node))->varno,
- ctxt->newRTE);
-
- ((Var *)(node))->varno = ctxt->newRTE;
- adjustVarnoIfReversedCol((Var *)node,
- ctxt->newRTE,
- ctxt->tentries);
- /* nothing more to do */
- break;
-
- case T_ArrayRef:
- {
- ArrayRef *array = (ArrayRef *) node;
-
- /*
- * Things are getting complicated here. We have found an
- * array subscripting operation. It's necessary to
- * examine all varno's found in this operation to make
- * sure, we're getting right. This covers cases where a
- * view selects a single index or complete array from a
- * base table or view.
- */
-
- /*
- * Look at expressions that evaluate upper array
- * indexes. Make sure all varno's are modified. This is
- * done by walking the expression tree recursively.
- */
- expression_tree_walker((Node *) array->refupperindexpr,
- replace_tlist_varno_walker,
- (void *)ctxt);
-
- expression_tree_walker((Node *) array->reflowerindexpr,
- replace_tlist_varno_walker,
- (void *)ctxt);
-
- expression_tree_walker((Node *) array->refexpr,
- replace_tlist_varno_walker,
- (void *)ctxt);
-
- expression_tree_walker((Node *) array->refassgnexpr,
- replace_tlist_varno_walker,
- (void *)ctxt);
- }
-
- default:
- break;
- }
-
- return expression_tree_walker(node, replace_tlist_varno_walker, ctxt);
-}
-
-/*
- * Adds RTEs to form a query tree.
- *
- * select has to be a valid initialized view definition query tree
- * (the function assumes that this query has passed the
- * is_select_query_updatable() function).
- */
-static Query *
-form_update_query(const Query *select, ViewDefColumnList tentries, CmdType type)
-{
- RangeTblEntry *rte;
- Oid reloid;
- Query *newquery;
-
- AssertArg(select);
- AssertArg(tentries);
-
- newquery = makeNode(Query);
- newquery->commandType = type;
-
- /* copy the range table entries */
- newquery->rtable = copyObject(select->rtable);
-
- /* prepare other stuff */
- newquery->canSetTag = true;
- newquery->jointree = makeNode(FromExpr);
-
- /*
- * Set result relation to the base relation.
- *
- * Since we currently only support updatable views with one
- * underlying table, we simply extract the one relation which
- * isn't labeled as *OLD* or *NEW*.
- */
- reloid = get_reloid_from_select(select, &(newquery->resultRelation), &rte);
- if (!OidIsValid(reloid))
- elog(ERROR, "could not retrieve base relation OID");
-
- Assert(newquery->resultRelation > 0);
-
- /* adjust inFromCl of result range table entry */
- rte->inFromCl = false;
-
- /* We don't need a target list for DELETE. */
- if (type != CMD_DELETE)
- {
- ViewExprContext ctxt;
- ListCell *cell;
-
- /* Copy all target entries. */
- newquery->targetList = copyObject(select->targetList);
-
- /*
- * Replace all varnos to point to the *NEW* node in all targetentry
- * expressions.
- */
-
- ctxt.newRTE = PRS2_NEW_VARNO;
- ctxt.tentries = tentries;
-
- foreach(cell, newquery->targetList)
- {
- Node *node = (Node *) lfirst(cell);
- expression_tree_walker(node,
- replace_tlist_varno_walker,
- (void *) &ctxt);
- }
- }
-
- return newquery;
-}
-
-/*
- * Rewrite a TargetEntry, based on the given arguments to match
- * the new Query tree of the new DELETE/UPDATE/INSERT rule and/or
- * its underlying base relation.
- *
- * form_te_for_update() needs to carefully reassign Varno's of
- * all Var expressions assigned to the given TargetEntry and to
- * adjust all type info values and attribute index locations so
- * that the rewritten TargetEntry corresponds to the correct
- * column in the underlying base relation.
- *
- * Someone should consider that columns could be in reversed
- * order in a view definition, so we need to take care to
- * "restore" the correct order of all columns in the target list
- * of the new view update rules.
- *
- * There's also some additional overhead if we have an array field
- * involved. In this case we have to loop recursively through the
- * array expressions to get all target entries right.
- */
-static void
-form_te_for_update(int2 attnum, Form_pg_attribute attrs, Oid baserelid,
- Expr *expr, TargetEntry *te_update)
-{
- /*
- * First, try if this is an array subscripting operation. If true, dive
- * recursively into the subscripting tree examining all varnos.
- */
-
- if (IsA(expr, ArrayRef))
- {
- ArrayRef *array = (ArrayRef *) expr;
-
- if (array->refassgnexpr != NULL)
- form_te_for_update(attnum, attrs, baserelid, array->refassgnexpr,
- te_update);
-
- if (array->refupperindexpr != NIL)
- {
- ListCell *cell;
-
- foreach(cell, array->refupperindexpr)
- form_te_for_update(attnum, attrs, baserelid, (Expr *) lfirst(cell), te_update);
- }
-
- if (array->reflowerindexpr != NIL)
- {
- ListCell *cell;
-
- foreach(cell, array->reflowerindexpr)
- form_te_for_update(attnum, attrs, baserelid, (Expr *) lfirst(cell), te_update);
- }
-
- if (array->refexpr != NULL)
- form_te_for_update(attnum, attrs, baserelid, array->refexpr,
- te_update);
- }
- else if (IsA(expr, Var))
- {
- /*
- * Base case of recursion: actually build the TargetEntry.
- */
- Var *upd_var = (Var *) (te_update->expr);
-
- upd_var->varattno = te_update->resno;
- upd_var->varoattno = te_update->resno;
-
- upd_var->vartype = attrs->atttypid;
- upd_var->vartypmod = attrs->atttypmod;
-
- upd_var->varnoold = upd_var->varno;
-
- te_update->resno = attnum;
- te_update->resname = pstrdup(get_attname(baserelid, attnum));
- te_update->ressortgroupref = 0;
- te_update->resorigcol = 0;
- te_update->resorigtbl = 0;
- te_update->resjunk = false;
- }
-}
-
-/*
- * Create the returning list for the given query tree. This allows
- * using RETURING in view update actions. Note that the function
- * creates the returning list from the target list of the given query
- * tree if src is set to NULL. This requires to call
- * build_update_target_list() on that query tree before. If src !=
- * NULL, the target list is created from this query tree instead.
- */
-static void
-create_rule_returning_list(Query *query, const Query *src, Index newRTE,
- ViewDefColumnList tentries)
-{
- ViewExprContext ctxt;
- ListCell *cell;
-
- ctxt.newRTE = newRTE;
- ctxt.tentries = tentries;
-
- /* determine target list source */
- if (src)
- query->returningList = copyObject(src->targetList);
- else
- query->returningList = copyObject(query->targetList);
-
- foreach(cell, query->returningList)
- expression_tree_walker((Node *) lfirst(cell),
- replace_tlist_varno_walker,
- (void *) &ctxt);
-}
-
-/*
- * Build the target list for a view UPDATE rule.
- *
- * Note: The function assumes a Query tree specified by update, which
- * was copied by form_update_query(). We need the original Query tree
- * to adjust the properties of each member of the TargetList of the
- * new query tree.
- */
-static void
-build_update_target_list(const Query *update, const Query *select,
- Relation baserel)
-{
- ListCell *cell1;
- ListCell *cell2;
-
- /*
- * This Assert() is appropriate, since we rely on a query tree
- * created by from_query(), which copies the target list from the
- * original query tree specified by the argument select, which
- * holds the current view definition. So both target lists have
- * to be equal in length.
- */
- Assert(list_length(update->targetList) == list_length(select->targetList));
-
- /*
- * Copy the target list of the view definition to the
- * returningList. This is required to support RETURNING clauses
- * in view update actions.
- */
- forboth(cell1, select->targetList, cell2, update->targetList)
- {
- TargetEntry *entry = (TargetEntry *) lfirst(cell1);
- TargetEntry *upd_entry = (TargetEntry *) lfirst(cell2);
- int attindex;
- Form_pg_attribute attr;
-
- if (entry->resorigcol > 0)
- /*
- * This column seems to have a different order than in the base
- * table. We get the attribute from the base relation referenced
- * by rel and create a new resdom. This new result domain is then
- * assigned instead of the old one.
- */
- attindex = entry->resorigcol;
- else
- attindex = entry->resno;
-
- attr = baserel->rd_att->attrs[attindex - 1];
-
- form_te_for_update(attindex, attr, baserel->rd_id, upd_entry->expr,
- upd_entry);
- }
-}
-
-/*
- * Examines the columns by the current view and initializes the lookup
- * table for all rearranged columns in base relations. The function
- * requires a relation tree initialized by get_base_base_relations().
- */
-static void
-read_rearranged_cols(ViewBaseRelation *tree)
-{
- AssertArg(tree);
-
- if (tree->defs)
- {
- int num_items = list_length(tree->defs);
- int i;
-
- /*
- * Traverse the relation tree and look on all base relations
- * for reversed column order in their target lists. We have
- * to perform a look-ahead-read on the tree, because we need
- * to know how much columns the next base relation has, to
- * allocate enough memory in tentries.
- *
- * Note that if we only have one base relation (a "real"
- * table, not a view) exists, we have nothing to do, because
- * this base relation cannot have a reversed column order
- * caused by a view definition query.
- */
- for (i = num_items - 1; i > 0; i--)
- {
- ViewBaseRelationItem *item_current;
- ViewBaseRelationItem *item_next;
- ViewBaseRelation *current;
- ViewBaseRelation *next;
-
- current = (ViewBaseRelation *) list_nth(tree->defs, i);
-
- /*
- * We look ahead for the next base relation. We can do
- * this here safely, because the loop condition terminates
- * before reaching the list head.
- */
- next = (ViewBaseRelation *) list_nth(tree->defs, i - 1);
-
- /*
- * Note that the code currently requires a simply updatable
- * relation tree. This means we handle one base relation
- * per loop, only.
- */
- Assert(next);
- Assert(current);
- Assert(list_length(next->defs) == 1);
- Assert(list_length(current->defs) == 1);
-
- item_current = (ViewBaseRelationItem *) list_nth(current->defs, 0);
- item_next = (ViewBaseRelationItem *) list_nth(next->defs, 0);
-
- /* allocate tentries buffer */
- item_current->tentries = (ViewDefColumnList) palloc(sizeof(TargetEntry *) * RelationGetNumberOfAttributes(item_next->rel));
-
- copyReversedTargetEntryPtr(item_current->rule->targetList,
- item_current->tentries);
- }
- }
-}
-
-/*------------------------------------------------------------------------------
- * Retrieves all relations from the view that can be considered a "base
- * relation". The function returns a list that holds lists of all relation
- * OIDs found for the view. The list is filled top down, that means the head of
- * the list holds the relations for the "highest" view in the tree.
- *
- * Consider this view definition tree where each node is a relation the above
- * node is based on:
- *
- * 1
- * / \
- * 2 3
- * / \ \
- * 4 5 6
- * /
- * 7
- *
- * The function will then return a list with the following layout:
- *
- * Listindex Node(s)
- * --------------------------
- * 1 7
- * 2 4 5 6
- * 3 2 3
- *
- * As you can see in the table, all relations that are "children" of the
- * given root relation (the view relation itself) are saved in the
- * tree, except the root node itself.
- *------------------------------------------------------------------------------
- */
-static void
-get_base_base_relations(const Query *view, Oid baserelid, List **list)
-{
- RangeTblEntry *entry;
- unsigned int offset = 1;
- ViewBaseRelation *childRel;
-
- if (!view)
- return;
-
- childRel = (ViewBaseRelation *) palloc(sizeof(ViewBaseRelation));
- childRel->defs = NIL;
- childRel->parentRelation = baserelid;
-
- /* Get all OIDs from the RTE list of view. */
- while ((entry = get_relation_RTE(view, &offset)) != NULL)
- {
- Relation rel;
- ViewBaseRelationItem *item;
-
- /*
- * Is this really a view or relation?
- */
- rel = relation_open(entry->relid, AccessShareLock);
-
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_VIEW)
- {
- /* don't need this one */
- relation_close(rel, AccessShareLock);
- continue;
- }
-
- item = (ViewBaseRelationItem *) palloc0(sizeof(ViewBaseRelationItem));
- item->rel = rel;
- item->rule = NULL;
-
- if (rel->rd_rel->relkind == RELKIND_VIEW)
- /*
- * Get the rule _RETURN expression tree for the specified
- * relation OID. We need this to recurse into the view
- * base relation tree.
- */
- item->rule = get_return_rule(rel);
-
- elog(DEBUG1, "extracted relation %s for relation tree",
- RelationGetRelationName(rel));
- childRel->defs = lappend(childRel->defs, item);
-
- /* recurse to any other child relations */
- if (item->rule)
- get_base_base_relations(item->rule, RelationGetRelid(rel), list);
-
- }
-
- if (childRel->defs)
- *list = lappend(*list, childRel);
-}
-
-static void
-copyReversedTargetEntryPtr(List *targetList, ViewDefColumnList targets)
-{
- ListCell *cell;
-
- AssertArg(targets);
- AssertArg(targetList);
-
- /* NOTE: We only reassign pointers. */
- foreach(cell, targetList)
- {
- Node *node = (Node *) lfirst(cell);
-
- if (IsA(node, TargetEntry))
- {
- /*
- * Look at the resdom's resorigcol to determine whether
- * this is a reversed column (meaning, it has a different
- * column number than the underlying base table).
- */
- TargetEntry *entry = (TargetEntry *) node;
-
- if (!IsA(entry->expr, Var))
- /* nothing to do here */
- continue;
-
- if (entry->resorigcol > 0 && entry->resno != entry->resorigcol)
- {
- /*
- * Save this TargetEntry to the appropiate place in
- * the lookup table. Do it only if not already
- * occupied (this could happen if the column is
- * specified more than one time in the view
- * definition).
- */
- if (targets[entry->resorigcol - 1] == NULL)
- targets[entry->resorigcol - 1] = entry;
- }
- }
- }
-}
-
-/*
- * Transforms the specified view definition into an INSERT, UPDATE, or
- * DELETE rule.
- *
- * Note: The function assumes that the specified query tree has passed the
- * is_select_query_updatable() function.
- */
-static void
-create_update_rule(Oid viewOid, const Query *select, const Relation baserel,
- ViewDefColumnList tentries,
- CmdType ruletype)
-{
- Query *newquery;
- Oid baserelid;
- Index baserti;
- RangeTblEntry *rte;
-
- AssertArg(tentries);
- AssertArg(baserel);
- AssertArg(select);
- AssertArg(ruletype == CMD_INSERT || ruletype == CMD_UPDATE || ruletype == CMD_DELETE);
-
- newquery = form_update_query(select, tentries, ruletype);
-
- /*
- * form_update_query() has prepared the jointree of the new UPDATE/DELETE rule.
- *
- * Now, our UPDATE rule needs range table references for the *NEW*
- * and base relation RTEs. A DELETE rule needs range table
- * references for the *OLD* and base relation RTEs.
- */
-
- baserelid = get_reloid_from_select(select, NULL, &rte);
- if (!OidIsValid(baserelid))
- elog(ERROR, "could not get the base relation from the view definition");
-
- baserti = get_rtindex_for_rel(newquery->rtable,
- rte->eref->aliasname);
- Assert(baserti > 0);
-
- rte = rt_fetch(baserti, newquery->rtable);
-
- if (ruletype != CMD_INSERT)
- {
- RangeTblRef *oldref;
- RangeTblRef *baseref;
-
- oldref = makeNode(RangeTblRef);
- oldref->rtindex = PRS2_OLD_VARNO;
-
- baseref = makeNode(RangeTblRef);
- baseref->rtindex = baserti;
-
- newquery->jointree->fromlist = list_make2(baseref, oldref);
-
- /* Create the WHERE condition qualification for the rule action. */
- form_where_for_updrule(select, &(newquery->jointree),
- baserel, baserti, PRS2_OLD_VARNO);
- }
-
- if (ruletype != CMD_DELETE)
- /*
- * We must reorder the columns in the targetlist to match the
- * underlying table. We do this after calling
- * form_where_for_updrule() because build_update_target_list()
- * relies on the original resdoms in the update tree.
- */
- build_update_target_list(newquery, select, baserel);
-
- /*
- * Create the returning list now that build_update_target_list()
- * has done the leg work.
- */
- if (ruletype == CMD_DELETE)
- create_rule_returning_list(newquery, select, PRS2_OLD_VARNO, tentries);
- else
- create_rule_returning_list(newquery, NULL, PRS2_NEW_VARNO, tentries);
-
- /* Set ACL bit */
- if (ruletype == CMD_INSERT)
- rte->requiredPerms |= ACL_INSERT;
- else if (ruletype == CMD_UPDATE)
- rte->requiredPerms |= ACL_UPDATE;
- else if (ruletype == CMD_DELETE)
- rte->requiredPerms |= ACL_DELETE;
-
- /* Create system rule */
- DefineQueryRewrite(pstrdup(get_auto_rule_name(ruletype)),
- viewOid, /* event_relid */
- NULL, /* WHERE clause */
- ruletype,
- true, /* is_instead */
- true, /* is_auto */
- false, /* replace */
- list_make1(newquery) /* action */);
-}
-
-/*
- * Checks the specified Query for updatability. Currently, "simply
- * updatable" rules are implemented.
- */
-static bool
-is_select_query_updatable(const Query *query)
-{
- ListCell *cell;
- List *seen_attnos;
-
- AssertArg(query);
- AssertArg(query->commandType == CMD_SELECT);
-
- /*
- * check for unsupported clauses in the view definition
- */
-
- if (query->hasAggs)
- {
- elog(DEBUG1, "view is not updatable because it uses an aggregate function");
- return false;
- }
-
- if (query->hasWindowFuncs)
- {
- elog(DEBUG1, "view is not updatable because it uses a window function");
- return false;
- }
-
- if (query->hasRecursive)
- {
- elog(DEBUG1, "view is not updatable because it contains a WITH RECURSIVE clause");
- return false;
- }
-
- if (query->cteList)
- {
- elog(DEBUG1, "view is not updatable because it contains a WITH clause");
- return false;
- }
-
- if (list_length(query->groupClause) >= 1)
- {
- elog(DEBUG1, "view is not updatable because it contains a GROUP BY clause");
- return false;
- }
-
- if (query->havingQual)
- {
- elog(DEBUG1, "view is not updatable because it contains a HAVING clause");
- return false;
- }
-
- if (list_length(query->distinctClause) >= 1)
- {
- elog(DEBUG1, "view is not updatable because it contains a DISTINCT clause");
- return false;
- }
-
- if (query->limitOffset)
- {
- elog(DEBUG1, "view is not updatable because it contains an OFFSET clause");
- return false;
- }
-
- if (query->limitCount)
- {
- elog(DEBUG1, "view is not updatable because it contains a LIMIT clause");
- return false;
- }
-
- if (query->setOperations)
- {
- elog(DEBUG1, "view is not updatable because it contains UNION or INTERSECT or EXCEPT");
- return false;
- }
-
- /*
- * Test for number of involved relations. Since we assume to
- * operate on a view definition SELECT query tree, we must count 3
- * rtable entries. Otherwise this seems not to be a view based on
- * a single relation.
- */
- if (list_length(query->rtable) > 3)
- {
- elog(DEBUG1, "view is not updatable because it has more than one underlying table");
- return false;
- }
-
- /* Any rtable entries involved? */
- if (list_length(query->rtable) < 3)
- {
- elog(DEBUG1, "view is not updatable because it has no underlying tables");
- return false;
- }
-
- /*
- * Walk down the target list and look for nodes that aren't Vars.
- * "Simply updatable" doesn't allow functions, host variables, or
- * constant expressions in the target list.
- *
- * Also, check if any of the target list entries are indexed array
- * expressions, which aren't supported.
- */
- seen_attnos = NIL;
-
- foreach(cell, query->targetList)
- {
- Node *node = (Node *) lfirst(cell);
-
- if (IsA(node, TargetEntry))
- {
- TargetEntry *te = (TargetEntry *) node;
-
- /*
- * TODO -- it would be nice to support Const nodes here as well
- * (but apparently it isn't in the standard)
- */
- if (!IsA(te->expr, Var) && !IsA(te->expr, ArrayRef))
- {
- elog(DEBUG1, "view is not updatable because select list contains a derived column");
- return false;
- }
-
- /* This is currently only partially implemented, but can be fixed. */
- if (IsA(te->expr, ArrayRef))
- {
- elog(DEBUG1, "view is not updatable because select list contains an array element reference");
- return false;
- }
-
- if (IsA(te->expr, Var))
- {
- Var *var = (Var *) te->expr;
-
- /* System columns aren't updatable. */
- if (var->varattno < 0)
- {
- elog(DEBUG1, "view is not updatable because select list references a system column");
- return false;
- }
-
- if (list_member_int(seen_attnos, var->varattno))
- {
- elog(DEBUG1, "view is not updatable because select list references the same column more than once");
- return false;
- }
- else
- seen_attnos = lappend_int(seen_attnos, var->varattno);
- }
- }
- }
-
- /*
- * Finally, check that all RTEs are acceptable. This rejects
- * table functions, which cannot ever be updatable, and also WITH
- * clauses.
- */
- foreach(cell, query->rtable)
- {
- RangeTblEntry *entry = (RangeTblEntry *) lfirst(cell);
-
- if (entry->rtekind != RTE_RELATION)
- {
- elog(DEBUG1, "view is not updatable because correlation \"%s\" is not a table",
- entry->eref->aliasname);
- return false;
- }
- }
-
- return true;
-}
-
-/*
- * Traverse the specified relation tree. The function stops at the
- * base relations at the leafs of the tree. If any of the relations
- * has more than one base relation, it is considered a not simply
- * updatable view and false is returned.
- */
-static bool
-check_reltree(ViewBaseRelation *node)
-{
- ListCell *cell;
-
- AssertArg(node);
-
- foreach(cell, node->defs)
- {
- /* Walk down the tree */
- ViewBaseRelation *relations = (ViewBaseRelation *) lfirst(cell);
-
- if (list_length(relations->defs) > 1)
- {
- elog(DEBUG1, "possible JOIN/UNION in view definition: %d", list_length(relations->defs));
- return false;
- }
- else if (list_length(relations->defs) == 1) {
- ViewBaseRelationItem *item = (ViewBaseRelationItem *) linitial(relations->defs);
-
- /* if the relation found is a view, check its updatability */
- if (item->rel->rd_rel->relkind == RELKIND_VIEW && !is_select_query_updatable(item->rule))
- {
- elog(DEBUG1, "base view \"%s\" is not updatable",
- RelationGetRelationName(item->rel));
- return false;
- }
- }
- }
-
- return true;
-}
-
-/*
- * Given a SELECT query tree, return the OID of the first RTE_RELATION range
- * table entry found that is not *NEW* nor *OLD*.
- *
- * Also sets the RangeTblEntry pointer into rel_entry, and the range
- * table index into rti, unless they are NULL.
- *
- * This function assumes that the specified query tree was checked by a
- * previous call to the is_select_query_updatable() function.
- */
-static Oid
-get_reloid_from_select(const Query *select, int *rti, RangeTblEntry **rel_entry)
-{
- ListCell *cell;
- Oid result = InvalidOid;
- int index;
-
- /* Check specified query tree. Return immediately on error. */
- if (select == NULL || select->commandType != CMD_SELECT)
- return InvalidOid;
-
- /*
- * We loop through the RTEs to get information about all involved
- * relations. We return the first OID we find in the list that is not
- * *NEW* nor *OLD*.
- */
- index = 0;
- foreach(cell, select->rtable)
- {
- RangeTblEntry *entry = (RangeTblEntry *) lfirst(cell);
-
- index++;
-
- if (entry == NULL)
- elog(ERROR, "null RTE pointer in get_reloid_from_select");
-
- elog(DEBUG1, "extracted range table entry for %u", entry->relid);
-
- /* Return the first RELATION rte we find */
- if (entry->rtekind == RTE_RELATION)
- {
- /*
- * XXX This is ugly. The parser prepends two RTEs with rtekind
- * RTE_RELATION named *NEW* and *OLD*. We have to exclude them by
- * name! It would be much better if it used RTE_SPECIAL
- * instead, but other parts of the system stop working if one
- * just changes it naively.
- */
- if (strncmp(entry->eref->aliasname, "*NEW*", 6) == 0
- || strncmp(entry->eref->aliasname, "*OLD*", 6) == 0)
- continue;
-
- result = entry->relid;
- if (rti != NULL)
- *rti = index;
- if (rel_entry != NULL)
- *rel_entry = entry;
- break;
- }
- }
-
- return result;
-}
-
-/*
- * get_return_rule: returns the _RETURN rule of a view as a Query node.
- */
-static Query *
-get_return_rule(Relation rel)
-{
- Query *query = NULL;
- int i;
-
- AssertArg(rel->rd_rel->relkind == RELKIND_VIEW);
-
- for (i = 0; i < rel->rd_rules->numLocks; i++)
- {
- RewriteRule *rule = rel->rd_rules->rules[i];
-
- if (rule->event == CMD_SELECT)
- {
- /* A _RETURN rule should have only one action */
- if (list_length(rule->actions) != 1)
- elog(ERROR, "invalid _RETURN rule action specification");
-
- query = linitial(rule->actions);
- break;
- }
- }
-
- return query;
-}
-
-/*------------------------------------------------------------------------------
- * Public functions
- *------------------------------------------------------------------------------
- */
-
-/*
- * CreateViewUpdateRules
- *
- * This is the main entry point to creating an updatable view's rules. Given a
- * rule definition, examine it, and create the rules if appropiate, or return
- * doing nothing if not.
- */
-void
-CreateViewUpdateRules(Oid viewOid, const Query *viewDef)
-{
- Relation baserel;
- Form_pg_attribute *attrs;
- ViewDefColumnList tentries;
- Oid baserelid;
- MemoryContext cxt;
- MemoryContext oldcxt;
- ViewBaseRelation *tree;
- ListCell *cell;
-
- /*
- * The routines in this file leak memory like crazy, so make sure we
- * allocate it all in an appropiate context.
- */
- cxt = AllocSetContextCreate(TopTransactionContext,
- "UpdateRulesContext",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
- oldcxt = MemoryContextSwitchTo(cxt);
-
- /*
- * Create the lookup table for the view definition target columns. We save
- * the RESDOMS in that manner to look quickly for reversed column orders.
- */
-
- baserelid = get_reloid_from_select(viewDef, NULL, NULL);
-
- /* Get relation tree */
- tree = (ViewBaseRelation *) palloc(sizeof(ViewBaseRelation));
-
- tree->parentRelation = InvalidOid;
- tree->defs = NIL;
- get_base_base_relations(viewDef, baserelid, &(tree->defs));
-
- /* Check the query tree for updatability */
- if (!check_reltree(tree) || !is_select_query_updatable(viewDef))
- {
- elog(DEBUG1, "view is not updatable");
- goto finish;
- }
-
- baserel = heap_open(baserelid, AccessShareLock);
- attrs = baserel->rd_att->attrs;
-
- /*
- * Copy TargetEntries to match the slot numbers in the target list with
- * their original column attribute number. Note that only pointers are
- * copied and they are valid only as long as the specified SELECT query
- * stays valid!
- */
- tentries = (ViewDefColumnList)
- palloc0(baserel->rd_rel->relnatts * sizeof(TargetEntry *));
-
- copyReversedTargetEntryPtr(viewDef->targetList, tentries);
-
- /*
- * Now do the same for the base relation tree. read_rearranged_cols
- * traverses the relation tree and performs a copyReversedTargetEntry()
- * call to each base relation.
- */
- read_rearranged_cols(tree);
-
- create_update_rule(viewOid, viewDef, baserel, tentries, CMD_INSERT);
- create_update_rule(viewOid, viewDef, baserel, tentries, CMD_DELETE);
- create_update_rule(viewOid, viewDef, baserel, tentries, CMD_UPDATE);
-
- ereport(NOTICE, (errmsg("CREATE VIEW has created automatic view update rules")));
-
- /* free remaining stuff */
- heap_close(baserel, NoLock);
-
-finish:
- /* get_base_base_relations leaves some open relations */
- foreach(cell, tree->defs)
- {
- ListCell *cell2;
- ViewBaseRelation *vbr = (ViewBaseRelation *) lfirst(cell);
-
- foreach(cell2, vbr->defs)
- {
- ViewBaseRelationItem *vbri = (ViewBaseRelationItem *) lfirst(cell2);
-
- relation_close(vbri->rel, NoLock);
- }
- }
-
- MemoryContextSwitchTo(oldcxt);
- MemoryContextDelete(cxt);
-}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 1cac276516..196ca0155f 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.283 2009/01/26 19:41:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.284 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -639,7 +639,6 @@ RelationBuildRuleLock(Relation relation)
rule->attrno = rewrite_form->ev_attr;
rule->enabled = rewrite_form->ev_enabled;
rule->isInstead = rewrite_form->is_instead;
- rule->is_auto = rewrite_form->is_auto;
/*
* Must use heap_getattr to fetch ev_action and ev_qual. Also, the
@@ -763,8 +762,6 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
return false;
if (!equal(rule1->actions, rule2->actions))
return false;
- if(rule1->is_auto != rule2->is_auto)
- return false;
}
}
else if (rlock2 != NULL)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f47333c605..cb6ae92a38 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.516 2009/01/22 20:16:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.517 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4003,17 +4003,7 @@ getRules(int *numRules)
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 80400)
- {
- appendPQExpBuffer(query, "SELECT "
- "tableoid, oid, rulename, "
- "ev_class as ruletable, ev_type, is_instead, "
- "ev_enabled "
- "FROM pg_rewrite "
- "WHERE NOT is_auto "
- "ORDER BY oid");
- }
- else if (g_fout->remoteVersion >= 80300)
+ if (g_fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT "
"tableoid, oid, rulename, "
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 35b6b844d9..2f70c70428 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.148 2009/01/22 17:27:54 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.149 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -304,6 +304,7 @@ typedef struct _ruleInfo
bool is_instead;
char ev_enabled;
bool separate; /* TRUE if must dump as separate item */
+ /* separate is always true for non-ON SELECT rules */
} RuleInfo;
typedef struct _triggerInfo
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 11349023d9..b83c948964 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.519 2009/01/22 20:16:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.520 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200901221
+#define CATALOG_VERSION_NO 200901271
#endif
diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h
index 2dc621e5fe..4c43898873 100644
--- a/src/include/catalog/pg_rewrite.h
+++ b/src/include/catalog/pg_rewrite.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.32 2009/01/22 17:27:54 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.33 2009/01/27 12:40:15 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -40,15 +40,6 @@ CATALOG(pg_rewrite,2618)
char ev_enabled;
bool is_instead;
- /*
- * is_auto: True if the rule was automatically generated (update
- * rules). This is tracked separately from the dependency system,
- * because we want to allow overwriting the automatic update
- * rules. So both automatically and manually generated rules have
- * dependency type AUTO.
- */
- bool is_auto;
-
/* NB: remaining fields must be accessed via heap_getattr */
text ev_qual;
text ev_action;
@@ -65,15 +56,14 @@ typedef FormData_pg_rewrite *Form_pg_rewrite;
* compiler constants for pg_rewrite
* ----------------
*/
-#define Natts_pg_rewrite 9
+#define Natts_pg_rewrite 8
#define Anum_pg_rewrite_rulename 1
#define Anum_pg_rewrite_ev_class 2
#define Anum_pg_rewrite_ev_attr 3
#define Anum_pg_rewrite_ev_type 4
#define Anum_pg_rewrite_ev_enabled 5
#define Anum_pg_rewrite_is_instead 6
-#define Anum_pg_rewrite_is_auto 7
-#define Anum_pg_rewrite_ev_qual 8
-#define Anum_pg_rewrite_ev_action 9
+#define Anum_pg_rewrite_ev_qual 7
+#define Anum_pg_rewrite_ev_action 8
#endif /* PG_REWRITE_H */
diff --git a/src/include/rewrite/prs2lock.h b/src/include/rewrite/prs2lock.h
index 5d039c21c0..70dbae514d 100644
--- a/src/include/rewrite/prs2lock.h
+++ b/src/include/rewrite/prs2lock.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.26 2009/01/22 17:27:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/prs2lock.h,v 1.27 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,7 +30,6 @@ typedef struct RewriteRule
List *actions;
char enabled;
bool isInstead;
- bool is_auto;
} RewriteRule;
/*
diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h
index 10936fab84..757957cf7f 100644
--- a/src/include/rewrite/rewriteDefine.h
+++ b/src/include/rewrite/rewriteDefine.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.32 2009/01/22 17:27:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.33 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,6 @@ extern void DefineQueryRewrite(char *rulename,
Node *event_qual,
CmdType event_type,
bool is_instead,
- bool is_auto,
bool replace,
List *action);
diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h
index f7d3c35465..7f007d1ca6 100644
--- a/src/include/rewrite/rewriteRemove.h
+++ b/src/include/rewrite/rewriteRemove.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/rewrite/rewriteRemove.h,v 1.26 2009/01/22 17:27:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/rewrite/rewriteRemove.h,v 1.27 2009/01/27 12:40:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,5 @@
extern void RemoveRewriteRule(Oid owningRel, const char *ruleName,
DropBehavior behavior, bool missing_ok);
extern void RemoveRewriteRuleById(Oid ruleOid);
-extern void RemoveAutomaticRulesOnEvent(Relation rel, CmdType event_type);
#endif /* REWRITEREMOVE_H */
diff --git a/src/include/rewrite/viewUpdate.h b/src/include/rewrite/viewUpdate.h
deleted file mode 100644
index 1423870846..0000000000
--- a/src/include/rewrite/viewUpdate.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*-------------------------------------------------------------------------
- *
- * viewUpdate.h
- *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $PostgreSQL: pgsql/src/include/rewrite/viewUpdate.h,v 1.1 2009/01/22 17:27:55 petere Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef VIEW_UPDATE_H
-#define VIEW_UPDATE_H
-
-#include "nodes/parsenodes.h"
-
-extern void
-CreateViewUpdateRules(Oid viewOid, const Query *viewDef);
-
-#endif /* VIEW_UPDATE_H */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 5ac24e5b3d..4768c8b186 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -132,7 +132,6 @@ ALTER INDEX onek_unique1 RENAME TO tmp_onek_unique1;
ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1;
-- renaming views
CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1;
-NOTICE: CREATE VIEW has created automatic view update rules
ALTER TABLE tmp_view RENAME TO tmp_view_new;
-- hack to ensure we get an indexscan here
ANALYZE tenk1;
@@ -593,7 +592,6 @@ alter table atacc1 alter oid drop not null;
ERROR: cannot alter system column "oid"
-- try creating a view and altering that, should fail
create view myview as select * from atacc1;
-NOTICE: CREATE VIEW has created automatic view update rules
alter table myview alter column test drop not null;
ERROR: "myview" is not a table
alter table myview alter column test set not null;
@@ -661,7 +659,6 @@ ERROR: column "c3" of relation "def_test" does not exist
-- to allow insertions into it, and then alter the view to add
-- a default
create view def_view_test as select * from def_test;
-NOTICE: CREATE VIEW has created automatic view update rules
create rule def_view_test_ins as
on insert to def_view_test
do instead insert into def_test select new.*;
@@ -845,7 +842,6 @@ alter table atacc1 drop xmin;
ERROR: cannot drop system column "xmin"
-- try creating a view and altering that, should fail
create view myview as select * from atacc1;
-NOTICE: CREATE VIEW has created automatic view update rules
select * from myview;
b | c | d
---+---+---
@@ -1440,7 +1436,6 @@ create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0));
NOTICE: CREATE TABLE will create implicit sequence "t1_f1_seq" for serial column "t1.f1"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
create view alter1.v1 as select * from alter1.t1;
-NOTICE: CREATE VIEW has created automatic view update rules
create function alter1.plus1(int) returns int as 'select $1+1' language sql;
create domain alter1.posint integer check (value > 0);
create type alter1.ctype as (f1 int, f2 text);
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 232bacfd6d..04383e43d2 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -27,10 +27,8 @@ CREATE TABLE viewtest_tbl (a int, b int);
COPY viewtest_tbl FROM stdin;
CREATE OR REPLACE VIEW viewtest AS
SELECT * FROM viewtest_tbl;
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE OR REPLACE VIEW viewtest AS
SELECT * FROM viewtest_tbl WHERE a > 10;
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT * FROM viewtest;
a | b
----+----
@@ -40,7 +38,6 @@ SELECT * FROM viewtest;
CREATE OR REPLACE VIEW viewtest AS
SELECT a, b FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT * FROM viewtest;
a | b
----+----
@@ -74,17 +71,13 @@ SET search_path TO temp_view_test, public;
CREATE TEMPORARY TABLE temp_table (a int, id int);
-- should be created in temp_view_test schema
CREATE VIEW v1 AS SELECT * FROM base_table;
-NOTICE: CREATE VIEW has created automatic view update rules
-- should be created in temp object schema
CREATE VIEW v1_temp AS SELECT * FROM temp_table;
NOTICE: view "v1_temp" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
-- should be created in temp object schema
CREATE TEMP VIEW v2_temp AS SELECT * FROM base_table;
-NOTICE: CREATE VIEW has created automatic view update rules
-- should be created in temp_views schema
CREATE VIEW temp_view_test.v2 AS SELECT * FROM base_table;
-NOTICE: CREATE VIEW has created automatic view update rules
-- should fail
CREATE VIEW temp_view_test.v3_temp AS SELECT * FROM temp_table;
NOTICE: view "v3_temp" will be a temporary view
@@ -114,25 +107,18 @@ CREATE VIEW v5_temp AS
NOTICE: view "v5_temp" will be a temporary view
-- subqueries
CREATE VIEW v4 AS SELECT * FROM base_table WHERE id IN (SELECT id FROM base_table2);
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v5 AS SELECT t1.id, t2.a FROM base_table t1, (SELECT * FROM base_table2) t2;
CREATE VIEW v6 AS SELECT * FROM base_table WHERE EXISTS (SELECT 1 FROM base_table2);
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v7 AS SELECT * FROM base_table WHERE NOT EXISTS (SELECT 1 FROM base_table2);
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v8 AS SELECT * FROM base_table WHERE EXISTS (SELECT 1);
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v6_temp AS SELECT * FROM base_table WHERE id IN (SELECT id FROM temp_table);
NOTICE: view "v6_temp" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v7_temp AS SELECT t1.id, t2.a FROM base_table t1, (SELECT * FROM temp_table) t2;
NOTICE: view "v7_temp" will be a temporary view
CREATE VIEW v8_temp AS SELECT * FROM base_table WHERE EXISTS (SELECT 1 FROM temp_table);
NOTICE: view "v8_temp" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v9_temp AS SELECT * FROM base_table WHERE NOT EXISTS (SELECT 1 FROM temp_table);
NOTICE: view "v9_temp" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
-- a view should also be temporary if it references a temporary view
CREATE VIEW v10_temp AS SELECT * FROM v7_temp;
NOTICE: view "v10_temp" will be a temporary view
@@ -144,10 +130,8 @@ NOTICE: view "v12_temp" will be a temporary view
CREATE SEQUENCE seq1;
CREATE TEMPORARY SEQUENCE seq1_temp;
CREATE VIEW v9 AS SELECT seq1.is_called FROM seq1;
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW v13_temp AS SELECT seq1_temp.is_called FROM seq1_temp;
NOTICE: view "v13_temp" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT relname FROM pg_class
WHERE relname LIKE 'v_'
AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'temp_view_test')
@@ -235,7 +219,6 @@ CREATE TEMP TABLE tmptbl (i int, j int);
CREATE VIEW pubview AS SELECT * FROM tbl1 WHERE tbl1.a
BETWEEN (SELECT d FROM tbl2 WHERE c = 1) AND (SELECT e FROM tbl3 WHERE f = 2)
AND EXISTS (SELECT g FROM tbl4 LEFT JOIN tbl3 ON tbl4.h = tbl3.f);
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT count(*) FROM pg_class where relname = 'pubview'
AND relnamespace IN (SELECT OID FROM pg_namespace WHERE nspname = 'testviewschm2');
count
@@ -249,7 +232,6 @@ BETWEEN (SELECT d FROM tbl2 WHERE c = 1) AND (SELECT e FROM tbl3 WHERE f = 2)
AND EXISTS (SELECT g FROM tbl4 LEFT JOIN tbl3 ON tbl4.h = tbl3.f)
AND NOT EXISTS (SELECT g FROM tbl4 LEFT JOIN tmptbl ON tbl4.h = tmptbl.j);
NOTICE: view "mytempview" will be a temporary view
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT count(*) FROM pg_class where relname LIKE 'mytempview'
And relnamespace IN (SELECT OID FROM pg_namespace WHERE nspname LIKE 'pg_temp%');
count
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 90f1bb86e1..092c90403a 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -13,7 +13,6 @@ ERROR: view "test_view_exists" does not exist
DROP VIEW IF EXISTS test_view_exists;
NOTICE: view "test_view_exists" does not exist, skipping
CREATE VIEW test_view_exists AS select * from test_exists;
-NOTICE: CREATE VIEW has created automatic view update rules
DROP VIEW IF EXISTS test_view_exists;
DROP VIEW test_view_exists;
ERROR: view "test_view_exists" does not exist
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
index 853ae94fdb..c0681d26e3 100644
--- a/src/test/regress/expected/plancache.out
+++ b/src/test/regress/expected/plancache.out
@@ -79,7 +79,6 @@ EXECUTE prepstmt2(123);
-- but should trigger invalidation anyway
CREATE TEMP VIEW pcacheview AS
SELECT * FROM pcachetest;
-NOTICE: CREATE VIEW has created automatic view update rules
PREPARE vprep AS SELECT * FROM pcacheview;
EXECUTE vprep;
q1 | q2
@@ -237,9 +236,6 @@ select cachebug();
NOTICE: table "temptable" does not exist, skipping
CONTEXT: SQL statement "drop table if exists temptable cascade"
PL/pgSQL function "cachebug" line 3 at SQL statement
-NOTICE: CREATE VIEW has created automatic view update rules
-CONTEXT: SQL statement "create temp view vv as select * from temptable"
-PL/pgSQL function "cachebug" line 5 at SQL statement
NOTICE: 1
NOTICE: 2
NOTICE: 3
@@ -252,9 +248,6 @@ select cachebug();
NOTICE: drop cascades to view vv
CONTEXT: SQL statement "drop table if exists temptable cascade"
PL/pgSQL function "cachebug" line 3 at SQL statement
-NOTICE: CREATE VIEW has created automatic view update rules
-CONTEXT: SQL statement "create temp view vv as select * from temptable"
-PL/pgSQL function "cachebug" line 5 at SQL statement
NOTICE: 1
NOTICE: 2
NOTICE: 3
diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out
index be5c476548..95dcea5a1d 100644
--- a/src/test/regress/expected/portals.out
+++ b/src/test/regress/expected/portals.out
@@ -1229,7 +1229,6 @@ ROLLBACK;
-- WHERE CURRENT OF may someday work with views, but today is not that day.
-- For now, just make sure it errors out cleanly.
CREATE TEMP VIEW ucview AS SELECT * FROM uctest;
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD
DELETE FROM uctest WHERE f1 = OLD.f1;
BEGIN;
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 88d1ab3b78..7d3b44b856 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -189,12 +189,9 @@ DELETE FROM atest3; -- ok
-- views
SET SESSION AUTHORIZATION regressuser3;
CREATE VIEW atestv1 AS SELECT * FROM atest1; -- ok
-NOTICE: CREATE VIEW has created automatic view update rules
/* The next *should* fail, but it's not implemented that way yet. */
CREATE VIEW atestv2 AS SELECT * FROM atest2;
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT * FROM atestv1; -- ok
a | b
---+-----
@@ -222,7 +219,6 @@ SELECT * FROM atestv3; -- ok
(0 rows)
CREATE VIEW atestv4 AS SELECT * FROM atestv3; -- nested view
-NOTICE: CREATE VIEW has created automatic view update rules
SELECT * FROM atestv4; -- ok
one | two | three
-----+-----+-------
diff --git a/src/test/regress/expected/returning.out b/src/test/regress/expected/returning.out
index 05afef0f19..b04f6f1a0e 100644
--- a/src/test/regress/expected/returning.out
+++ b/src/test/regress/expected/returning.out
@@ -195,7 +195,6 @@ SELECT * FROM foochild;
DROP TABLE foochild;
-- Rules and views
CREATE TEMP VIEW voo AS SELECT f1, f2 FROM foo;
-NOTICE: CREATE VIEW has created automatic view update rules
CREATE RULE voo_i AS ON INSERT TO voo DO INSTEAD
INSERT INTO foo VALUES(new.*, 57);
INSERT INTO voo VALUES(11,'zit');
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e0618abd67..2daa79d732 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -10,7 +10,6 @@ create table rtest_t1 (a int4, b int4);
create table rtest_t2 (a int4, b int4);
create table rtest_t3 (a int4, b int4);
create view rtest_v1 as select * from rtest_t1;
-NOTICE: CREATE VIEW has created automatic view update rules
create rule rtest_v1_ins as on insert to rtest_v1 do instead
insert into rtest_t1 values (new.a, new.b);
create rule rtest_v1_upd as on update to rtest_v1 do instead
@@ -756,12 +755,9 @@ create table rtest_view3 (a int4, b text);
create table rtest_view4 (a int4, b text, c int4);
create view rtest_vview1 as select a, b from rtest_view1 X
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
-NOTICE: CREATE VIEW has created automatic view update rules
create view rtest_vview2 as select a, b from rtest_view1 where v;
-NOTICE: CREATE VIEW has created automatic view update rules
create view rtest_vview3 as select a, b from rtest_vview2 X
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
-NOTICE: CREATE VIEW has created automatic view update rules
create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
from rtest_view1 X, rtest_view2 Y
where X.a = Y.a
@@ -1337,8 +1333,8 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
- tablename | rulename | definition
----------------+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ tablename | rulename | definition
+---------------+-----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
pg_settings | pg_settings_n | CREATE RULE pg_settings_n AS ON UPDATE TO pg_settings DO INSTEAD NOTHING;
pg_settings | pg_settings_u | CREATE RULE pg_settings_u AS ON UPDATE TO pg_settings WHERE (new.name = old.name) DO SELECT set_config(old.name, new.setting, false) AS set_config;
rtest_emp | rtest_emp_del | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money, old.salary);
@@ -1363,21 +1359,12 @@ SELECT tablename, rulename, definition FROM pg_rules
rtest_v1 | rtest_v1_del | CREATE RULE rtest_v1_del AS ON DELETE TO rtest_v1 DO INSTEAD DELETE FROM rtest_t1 WHERE (rtest_t1.a = old.a);
rtest_v1 | rtest_v1_ins | CREATE RULE rtest_v1_ins AS ON INSERT TO rtest_v1 DO INSTEAD INSERT INTO rtest_t1 (a, b) VALUES (new.a, new.b);
rtest_v1 | rtest_v1_upd | CREATE RULE rtest_v1_upd AS ON UPDATE TO rtest_v1 DO INSTEAD UPDATE rtest_t1 SET a = new.a, b = new.b WHERE (rtest_t1.a = old.a);
- rtest_vview1 | _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO rtest_vview1 DO INSTEAD DELETE FROM rtest_view1 x WHERE ((((old.a IS NULL) AND (x.a IS NULL)) OR (old.a = x.a)) AND (((old.b IS NULL) AND (x.b IS NULL)) OR (old.b = x.b))) RETURNING old.a, old.b;
- rtest_vview1 | _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO rtest_vview1 DO INSTEAD INSERT INTO rtest_view1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- rtest_vview1 | _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO rtest_vview1 DO INSTEAD UPDATE rtest_view1 x SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (x.a IS NULL)) OR (old.a = x.a)) AND (((old.b IS NULL) AND (x.b IS NULL)) OR (old.b = x.b))) RETURNING new.a, new.b;
- rtest_vview2 | _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO rtest_vview2 DO INSTEAD DELETE FROM rtest_view1 WHERE ((((old.a IS NULL) AND (rtest_view1.a IS NULL)) OR (old.a = rtest_view1.a)) AND (((old.b IS NULL) AND (rtest_view1.b IS NULL)) OR (old.b = rtest_view1.b))) RETURNING old.a, old.b;
- rtest_vview2 | _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO rtest_vview2 DO INSTEAD INSERT INTO rtest_view1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- rtest_vview2 | _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO rtest_vview2 DO INSTEAD UPDATE rtest_view1 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (rtest_view1.a IS NULL)) OR (old.a = rtest_view1.a)) AND (((old.b IS NULL) AND (rtest_view1.b IS NULL)) OR (old.b = rtest_view1.b))) RETURNING new.a, new.b;
- rtest_vview3 | _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO rtest_vview3 DO INSTEAD DELETE FROM rtest_vview2 x WHERE ((((old.a IS NULL) AND (x.a IS NULL)) OR (old.a = x.a)) AND (((old.b IS NULL) AND (x.b IS NULL)) OR (old.b = x.b))) RETURNING old.a, old.b;
- rtest_vview3 | _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO rtest_vview3 DO INSTEAD INSERT INTO rtest_vview2 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- rtest_vview3 | _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO rtest_vview3 DO INSTEAD UPDATE rtest_vview2 x SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (x.a IS NULL)) OR (old.a = x.a)) AND (((old.b IS NULL) AND (x.b IS NULL)) OR (old.b = x.b))) RETURNING new.a, new.b;
shoelace | shoelace_del | CREATE RULE shoelace_del AS ON DELETE TO shoelace DO INSTEAD DELETE FROM shoelace_data WHERE (shoelace_data.sl_name = old.sl_name);
shoelace | shoelace_ins | CREATE RULE shoelace_ins AS ON INSERT TO shoelace DO INSTEAD INSERT INTO shoelace_data (sl_name, sl_avail, sl_color, sl_len, sl_unit) VALUES (new.sl_name, new.sl_avail, new.sl_color, new.sl_len, new.sl_unit);
shoelace | shoelace_upd | CREATE RULE shoelace_upd AS ON UPDATE TO shoelace DO INSTEAD UPDATE shoelace_data SET sl_name = new.sl_name, sl_avail = new.sl_avail, sl_color = new.sl_color, sl_len = new.sl_len, sl_unit = new.sl_unit WHERE (shoelace_data.sl_name = old.sl_name);
shoelace_data | log_shoelace | CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE (new.sl_avail <> old.sl_avail) DO INSERT INTO shoelace_log (sl_name, sl_avail, log_who, log_when) VALUES (new.sl_name, new.sl_avail, 'Al Bundy'::name, 'Thu Jan 01 00:00:00 1970'::timestamp without time zone);
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);
-(38 rows)
+(29 rows)
--
-- CREATE OR REPLACE RULE
@@ -1479,7 +1466,6 @@ insert into test_2 (name) values ('Test 4');
insert into test_3 (name) values ('Test 5');
insert into test_3 (name) values ('Test 6');
create view id_ordered as select * from id order by id;
-NOTICE: CREATE VIEW has created automatic view update rules
create rule update_id_ordered as on update to id_ordered
do instead update id set name = new.name where id = old.id;
select * from id_ordered;
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index b30fdcbb80..f6dbc0212c 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -349,7 +349,6 @@ create temp table shipped (
);
create temp view shipped_view as
select * from shipped where ttype = 'wt';
-NOTICE: CREATE VIEW has created automatic view update rules
create rule shipped_view_insert as on insert to shipped_view do instead
insert into shipped values('wt', new.ordnum, new.partnum, new.value);
insert into parts (partnum, cost) values (1, 1234.56);
diff --git a/src/test/regress/expected/view_update.out b/src/test/regress/expected/view_update.out
deleted file mode 100644
index 09c2d4f6f5..0000000000
--- a/src/test/regress/expected/view_update.out
+++ /dev/null
@@ -1,370 +0,0 @@
-CREATE TABLE vutest1 (a integer, b text);
-INSERT INTO vutest1 VALUES (1, 'one');
-INSERT INTO vutest1 VALUES (2, 'two');
--- simple view updatability conditions
-CREATE VIEW vutestv1 AS SELECT a, b FROM vutest1;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv2 AS SELECT * FROM vutest1;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv3 AS SELECT b, a FROM vutest1;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv4 AS SELECT a, b FROM vutest1 WHERE a < 5;
-NOTICE: CREATE VIEW has created automatic view update rules
--- not updatable tests:
-CREATE VIEW vutestv5 AS SELECT sum(a) FROM vutest1; -- aggregate function
-CREATE VIEW vutestv6 AS SELECT b FROM vutest1 GROUP BY b; -- GROUP BY
-CREATE VIEW vutestv7 AS SELECT l.b AS x, r.b AS y FROM vutest1 l, vutest1 r WHERE r.a = l.a; -- JOIN
-CREATE VIEW vutestv8 AS SELECT 42; -- no table
-CREATE VIEW vutestv9 AS SELECT a * 2 AS x, b || b AS y FROM vutest1; -- derived columns
-CREATE VIEW vutestv10 AS SELECT a AS x, a AS y FROM vutest1; -- column referenced more than once
-CREATE VIEW vutestv11 AS SELECT * FROM generate_series(1, 5); -- table function
-CREATE VIEW vutestv12 AS SELECT xmin, xmax, a, b FROM vutest1; -- system columns
-CREATE VIEW vutestv13 AS SELECT DISTINCT a, b FROM vutest1; -- DISTINCT
-CREATE VIEW vutestv14 AS SELECT a, b FROM vutest1 WHERE a > (SELECT avg(a) FROM vutest1); -- *is* updatable, but SQL standard disallows this
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv15 AS SELECT a, b FROM vutest1 UNION ALL SELECT a, b FROM vutest1; -- UNION
-CREATE VIEW vutestv16 AS SELECT x, y FROM (SELECT * FROM vutest1) AS foo (x, y); -- subquery ("derived table"); SQL standard allows this
-CREATE VIEW vutestv17 AS SELECT a, 5, b FROM vutest1; -- constant
-CREATE VIEW vutestv18 AS SELECT a, b FROM vutest1 LIMIT 1; -- LIMIT
-CREATE VIEW vutestv19 AS SELECT a, b FROM vutest1 OFFSET 1; -- OFFSET
-CREATE VIEW vutestv101 AS SELECT a, rank() OVER (PARTITION BY a ORDER BY b DESC) FROM vutest1; -- window function
-CREATE VIEW vutestv102 AS WITH foo AS (SELECT a, b FROM vutest1) SELECT * FROM foo; -- SQL standard allows this
-CREATE VIEW vutestv103 AS WITH RECURSIVE t(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM t) SELECT a FROM vutest1; -- recursive
-INSERT INTO vutestv1 VALUES (3, 'three');
-INSERT INTO vutestv2 VALUES (4, 'four');
-INSERT INTO vutestv3 VALUES (5, 'five'); -- fail
-ERROR: invalid input syntax for integer: "five"
-LINE 1: INSERT INTO vutestv3 VALUES (5, 'five');
- ^
-INSERT INTO vutestv3 VALUES ('five', 5);
-INSERT INTO vutestv3 (a, b) VALUES (6, 'six');
-INSERT INTO vutestv4 VALUES (7, 'seven'); -- ok, but would be check option issue
-INSERT INTO vutestv5 VALUES (8); -- fail
-ERROR: view is not updatable
-HINT: You need an unconditional ON INSERT DO INSTEAD rule.
-SELECT * FROM vutest1;
- a | b
----+-------
- 1 | one
- 2 | two
- 3 | three
- 4 | four
- 5 | five
- 6 | six
- 7 | seven
-(7 rows)
-
-SELECT * FROM vutestv1;
- a | b
----+-------
- 1 | one
- 2 | two
- 3 | three
- 4 | four
- 5 | five
- 6 | six
- 7 | seven
-(7 rows)
-
-SELECT * FROM vutestv2;
- a | b
----+-------
- 1 | one
- 2 | two
- 3 | three
- 4 | four
- 5 | five
- 6 | six
- 7 | seven
-(7 rows)
-
-SELECT * FROM vutestv3;
- b | a
--------+---
- one | 1
- two | 2
- three | 3
- four | 4
- five | 5
- six | 6
- seven | 7
-(7 rows)
-
-SELECT * FROM vutestv4;
- a | b
----+-------
- 1 | one
- 2 | two
- 3 | three
- 4 | four
-(4 rows)
-
-SELECT * FROM vutestv5;
- sum
------
- 28
-(1 row)
-
-UPDATE vutestv1 SET b = 'a lot' WHERE a = 7;
-DELETE FROM vutestv2 WHERE a = 1;
-UPDATE vutestv4 SET b = b || '!' WHERE a > 1;
-DELETE FROM vutestv4 WHERE a > 3;
-UPDATE vutestv6 SET b = 37; -- fail
-ERROR: view is not updatable
-HINT: You need an unconditional ON UPDATE DO INSTEAD rule.
-DELETE FROM vutestv5; -- fail
-ERROR: view is not updatable
-HINT: You need an unconditional ON DELETE DO INSTEAD rule.
-SELECT * FROM vutest1 ORDER BY a, b;
- a | b
----+--------
- 2 | two!
- 3 | three!
- 5 | five
- 6 | six
- 7 | a lot
-(5 rows)
-
-SELECT * FROM vutestv1 ORDER BY a, b;
- a | b
----+--------
- 2 | two!
- 3 | three!
- 5 | five
- 6 | six
- 7 | a lot
-(5 rows)
-
-SELECT * FROM vutestv2 ORDER BY a, b;
- a | b
----+--------
- 2 | two!
- 3 | three!
- 5 | five
- 6 | six
- 7 | a lot
-(5 rows)
-
-SELECT * FROM vutestv4 ORDER BY a, b;
- a | b
----+--------
- 2 | two!
- 3 | three!
-(2 rows)
-
-TRUNCATE TABLE vutest1;
--- views on views
-CREATE VIEW vutestv20 AS SELECT a AS x, b AS y FROM vutestv1;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv21 AS SELECT x AS a FROM vutestv20 WHERE x % 2 = 0;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv22 AS SELECT sum(a) FROM vutestv21; -- not updatable
-CREATE VIEW vutestv23 AS SELECT * FROM vutestv12; -- not updatable
-INSERT INTO vutestv20 (x, y) VALUES (1, 'one');
-INSERT INTO vutestv20 (x, y) VALUES (3, 'three');
-INSERT INTO vutestv21 VALUES (2);
-SELECT * FROM vutest1;
- a | b
----+-------
- 1 | one
- 3 | three
- 2 |
-(3 rows)
-
-SELECT * FROM vutestv20;
- x | y
----+-------
- 1 | one
- 3 | three
- 2 |
-(3 rows)
-
-SELECT * FROM vutestv21;
- a
----
- 2
-(1 row)
-
-UPDATE vutestv20 SET y = 'eins' WHERE x = 1;
-UPDATE vutestv21 SET a = 222;
-SELECT * FROM vutest1;
- a | b
------+-------
- 3 | three
- 1 | eins
- 222 |
-(3 rows)
-
-SELECT * FROM vutestv20;
- x | y
------+-------
- 3 | three
- 1 | eins
- 222 |
-(3 rows)
-
-SELECT * FROM vutestv21;
- a
------
- 222
-(1 row)
-
-DELETE FROM vutestv20 WHERE x = 3;
-SELECT * FROM vutest1;
- a | b
------+------
- 1 | eins
- 222 |
-(2 rows)
-
-SELECT * FROM vutestv20;
- x | y
------+------
- 1 | eins
- 222 |
-(2 rows)
-
-SELECT * FROM vutestv21;
- a
------
- 222
-(1 row)
-
--- insert tests
-CREATE TABLE vutest2 (a int PRIMARY KEY, b text NOT NULL, c text NOT NULL DEFAULT 'foo');
-NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "vutest2_pkey" for table "vutest2"
-CREATE VIEW vutestv30 AS SELECT a, b, c FROM vutest2;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv31 AS SELECT a, b FROM vutest2;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv32 AS SELECT a, c FROM vutest2;
-NOTICE: CREATE VIEW has created automatic view update rules
-INSERT INTO vutestv30 VALUES (1, 'one', 'eins');
-INSERT INTO vutestv31 VALUES (2, 'two');
-INSERT INTO vutestv32 VALUES (3, 'drei'); -- fail
-ERROR: null value in column "b" violates not-null constraint
-UPDATE vutestv31 SET a = 22 WHERE a = 2;
-UPDATE vutestv32 SET c = 'drei!' WHERE a = 3;
-SELECT rulename, definition FROM pg_rules WHERE tablename LIKE 'vutestv%' ORDER BY tablename, rulename;
- rulename | definition
-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv1 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv1 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv1 DO INSTEAD UPDATE vutest1 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING new.a, new.b;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv14 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv14 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv14 DO INSTEAD UPDATE vutest1 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING new.a, new.b;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv2 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv2 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv2 DO INSTEAD UPDATE vutest1 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING new.a, new.b;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv20 DO INSTEAD DELETE FROM vutestv1 WHERE ((((old.x IS NULL) AND (vutestv1.a IS NULL)) OR (old.x = vutestv1.a)) AND (((old.y IS NULL) AND (vutestv1.b IS NULL)) OR (old.y = vutestv1.b))) RETURNING old.x, old.y;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv20 DO INSTEAD INSERT INTO vutestv1 (a, b) VALUES (new.x, new.y) RETURNING new.x AS a, new.y AS b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv20 DO INSTEAD UPDATE vutestv1 SET a = new.x, b = new.y WHERE ((((old.x IS NULL) AND (vutestv1.a IS NULL)) OR (old.x = vutestv1.a)) AND (((old.y IS NULL) AND (vutestv1.b IS NULL)) OR (old.y = vutestv1.b))) RETURNING new.x AS a, new.y AS b;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv21 DO INSTEAD DELETE FROM vutestv20 WHERE ((((old.a IS NULL) AND (vutestv20.x IS NULL)) OR (old.a = vutestv20.x))) RETURNING old.a;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv21 DO INSTEAD INSERT INTO vutestv20 (x) VALUES (new.a) RETURNING new.a AS x;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv21 DO INSTEAD UPDATE vutestv20 SET x = new.a WHERE ((((old.a IS NULL) AND (vutestv20.x IS NULL)) OR (old.a = vutestv20.x))) RETURNING new.a AS x;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv3 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b)) AND (((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a))) RETURNING old.b, old.a;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv3 DO INSTEAD INSERT INTO vutest1 (b, a) VALUES (new.b, new.a) RETURNING new.a AS b, new.b AS a;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv3 DO INSTEAD UPDATE vutest1 SET b = new.b, a = new.a WHERE ((((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b)) AND (((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a))) RETURNING new.a AS b, new.b AS a;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv30 DO INSTEAD DELETE FROM vutest2 WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.b IS NULL) AND (vutest2.b IS NULL)) OR (old.b = vutest2.b) OR (((old.c IS NULL) AND (vutest2.c IS NULL)) OR (old.c = vutest2.c)))) RETURNING old.a, old.b, old.c;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv30 DO INSTEAD INSERT INTO vutest2 (a, b, c) VALUES (new.a, new.b, new.c) RETURNING new.a, new.b, new.c;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv30 DO INSTEAD UPDATE vutest2 SET a = new.a, b = new.b, c = new.c WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.b IS NULL) AND (vutest2.b IS NULL)) OR (old.b = vutest2.b) OR (((old.c IS NULL) AND (vutest2.c IS NULL)) OR (old.c = vutest2.c)))) RETURNING new.a, new.b, new.c;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv31 DO INSTEAD DELETE FROM vutest2 WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.b IS NULL) AND (vutest2.b IS NULL)) OR (old.b = vutest2.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv31 DO INSTEAD INSERT INTO vutest2 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv31 DO INSTEAD UPDATE vutest2 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.b IS NULL) AND (vutest2.b IS NULL)) OR (old.b = vutest2.b))) RETURNING new.a, new.b;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv32 DO INSTEAD DELETE FROM vutest2 WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.c IS NULL) AND (vutest2.c IS NULL)) OR (old.c = vutest2.c))) RETURNING old.a, old.c;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv32 DO INSTEAD INSERT INTO vutest2 (a, c) VALUES (new.a, new.c) RETURNING new.a, new.c;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv32 DO INSTEAD UPDATE vutest2 SET a = new.a, c = new.c WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.c IS NULL) AND (vutest2.c IS NULL)) OR (old.c = vutest2.c))) RETURNING new.a, new.c;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv4 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv4 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv4 DO INSTEAD UPDATE vutest1 SET a = new.a, b = new.b WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING new.a, new.b;
-(30 rows)
-
--- interaction of manual and automatic rules, view replacement
-CREATE VIEW vutestv40 AS SELECT a, b FROM vutest1;
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE RULE zmy_update AS ON UPDATE TO vutestv40 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE RULE "_INSERT" AS ON INSERT TO vutestv40 DO INSTEAD DELETE FROM vutest1; -- replaces automatic _INSERT rule
-CREATE RULE zmy_delete AS ON DELETE TO vutestv40 DO ALSO DELETE FROM vutest1; -- leaves automatic _DELETE rule (because of ALSO)
-CREATE VIEW vutestv41 AS SELECT a + 1 AS aa, b FROM vutest1; -- not updatable
-CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv41 DO INSTEAD UPDATE vutest1 SET a = new.aa - 1, b = new.b WHERE a = old.aa - 1 AND b = old.b;
-CREATE OR REPLACE VIEW vutestv41 AS SELECT a AS aa, b FROM vutest1; -- *now* updatable, manual _UPDATE rule stays
-WARNING: automatic UPDATE rule not created because manually created UPDATE rule exists
-HINT: If you prefer to have the automatic rule, drop the manually created rule and run CREATE OR REPLACE VIEW again.
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv42 AS SELECT a + 1 AS aa, b FROM vutest1; -- not updatable
-CREATE RULE zmy_update AS ON UPDATE TO vutestv42 DO INSTEAD UPDATE vutest1 SET a = new.aa - 1, b = new.b WHERE a = old.aa - 1 AND b = old.b;
-CREATE OR REPLACE VIEW vutestv42 AS SELECT a AS aa, b FROM vutest1; -- *now* updatable, zmy_update stays, no _UPDATE created
-WARNING: automatic UPDATE rule not created because manually created UPDATE rule exists
-HINT: If you prefer to have the automatic rule, drop the manually created rule and run CREATE OR REPLACE VIEW again.
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE VIEW vutestv43 AS SELECT a AS aa, b FROM vutest1; -- updatable
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE RULE zmy_update AS ON UPDATE TO vutestv43 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE OR REPLACE VIEW vutestv43 AS SELECT a + 1 AS aa, b FROM vutest1; -- no longer updatable, automatic rules are deleted, manual rules kept
-CREATE VIEW vutestv44 AS SELECT a, b FROM vutest1; -- updatable
-NOTICE: CREATE VIEW has created automatic view update rules
-CREATE RULE zmy_update AS ON UPDATE TO vutestv44 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE OR REPLACE VIEW vutestv44 AS SELECT a, b FROM vutest2; -- automatic update rules are updated, manual rules kept
-WARNING: automatic UPDATE rule not created because manually created UPDATE rule exists
-HINT: If you prefer to have the automatic rule, drop the manually created rule and run CREATE OR REPLACE VIEW again.
-NOTICE: CREATE VIEW has created automatic view update rules
-SELECT rulename, definition FROM pg_rules WHERE tablename LIKE 'vutestv4_' ORDER BY tablename, rulename;
- rulename | definition
-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv40 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.a IS NULL) AND (vutest1.a IS NULL)) OR (old.a = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv40 DO INSTEAD DELETE FROM vutest1;
- zmy_delete | CREATE RULE zmy_delete AS ON DELETE TO vutestv40 DO DELETE FROM vutest1;
- zmy_update | CREATE RULE zmy_update AS ON UPDATE TO vutestv40 DO INSTEAD DELETE FROM vutest1;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv41 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.aa IS NULL) AND (vutest1.a IS NULL)) OR (old.aa = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.aa, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv41 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.aa, new.b) RETURNING new.aa AS a, new.b;
- _UPDATE | CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv41 DO INSTEAD UPDATE vutest1 SET a = (new.aa - 1), b = new.b WHERE ((vutest1.a = (old.aa - 1)) AND (vutest1.b = old.b));
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv42 DO INSTEAD DELETE FROM vutest1 WHERE ((((old.aa IS NULL) AND (vutest1.a IS NULL)) OR (old.aa = vutest1.a)) AND (((old.b IS NULL) AND (vutest1.b IS NULL)) OR (old.b = vutest1.b))) RETURNING old.aa, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv42 DO INSTEAD INSERT INTO vutest1 (a, b) VALUES (new.aa, new.b) RETURNING new.aa AS a, new.b;
- zmy_update | CREATE RULE zmy_update AS ON UPDATE TO vutestv42 DO INSTEAD UPDATE vutest1 SET a = (new.aa - 1), b = new.b WHERE ((vutest1.a = (old.aa - 1)) AND (vutest1.b = old.b));
- zmy_update | CREATE RULE zmy_update AS ON UPDATE TO vutestv43 DO INSTEAD DELETE FROM vutest1;
- _DELETE | CREATE RULE "_DELETE" AS ON DELETE TO vutestv44 DO INSTEAD DELETE FROM vutest2 WHERE ((((old.a IS NULL) AND (vutest2.a IS NULL)) OR (old.a = vutest2.a)) AND (((old.b IS NULL) AND (vutest2.b IS NULL)) OR (old.b = vutest2.b))) RETURNING old.a, old.b;
- _INSERT | CREATE RULE "_INSERT" AS ON INSERT TO vutestv44 DO INSTEAD INSERT INTO vutest2 (a, b) VALUES (new.a, new.b) RETURNING new.a, new.b;
- zmy_update | CREATE RULE zmy_update AS ON UPDATE TO vutestv44 DO INSTEAD DELETE FROM vutest1;
-(14 rows)
-
--- ACL
-CREATE USER regressuser1;
-CREATE USER regressuser2;
-GRANT SELECT, INSERT, UPDATE ON vutest1 TO regressuser1;
-SET ROLE regressuser1;
-CREATE VIEW vutestv50 AS SELECT a, b FROM vutest1;
-NOTICE: CREATE VIEW has created automatic view update rules
-GRANT SELECT, UPDATE, DELETE ON vutestv50 TO regressuser2;
-SELECT * FROM vutestv50;
- a | b
------+------
- 1 | eins
- 222 |
-(2 rows)
-
-INSERT INTO vutestv50 VALUES (0, 'zero');
-UPDATE vutestv50 SET a = 1;
-UPDATE vutestv50 SET a = 2 WHERE a = 1;
-DELETE FROM vutestv50; -- ERROR
-ERROR: permission denied for relation vutest1
-RESET ROLE;
-SET ROLE regressuser2;
-SELECT * FROM vutestv50;
- a | b
----+------
- 2 | eins
- 2 |
- 2 | zero
-(3 rows)
-
-INSERT INTO vutestv50 VALUES (0, 'zero'); -- ERROR
-ERROR: permission denied for relation vutestv50
-UPDATE vutestv50 SET a = 1;
-UPDATE vutestv50 SET a = 2 WHERE a = 1;
-DELETE FROM vutestv50; -- ERROR on vutest1
-ERROR: permission denied for relation vutest1
-RESET ROLE;
-DROP VIEW vutestv50;
-REVOKE ALL PRIVILEGES ON vutest1 FROM regressuser1;
-DROP USER regressuser1, regressuser2;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 300a182cee..7b4425b940 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -1,5 +1,5 @@
# ----------
-# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.54 2009/01/22 17:27:55 petere Exp $
+# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.55 2009/01/27 12:40:15 petere Exp $
#
# By convention, we put no more than twenty tests in any one parallel group;
# this limits the number of connections needed to run the tests.
@@ -79,8 +79,6 @@ test: misc
# ----------
test: select_views portals_p2 rules foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window
-test: view_update
-
# ----------
# Another group of parallel tests
# NB: temp.sql does a reconnect which transiently uses 2 connections,
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 2773cf891f..ba93ea8520 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.51 2009/01/22 17:27:55 petere Exp $
+# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.52 2009/01/27 12:40:15 petere Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
@@ -100,7 +100,6 @@ test: tsearch
test: tsdicts
test: foreign_data
test: window
-test: view_update
test: plancache
test: limit
test: plpgsql
diff --git a/src/test/regress/sql/view_update.sql b/src/test/regress/sql/view_update.sql
deleted file mode 100644
index d6ece26b15..0000000000
--- a/src/test/regress/sql/view_update.sql
+++ /dev/null
@@ -1,168 +0,0 @@
-CREATE TABLE vutest1 (a integer, b text);
-INSERT INTO vutest1 VALUES (1, 'one');
-INSERT INTO vutest1 VALUES (2, 'two');
-
-
--- simple view updatability conditions
-
-CREATE VIEW vutestv1 AS SELECT a, b FROM vutest1;
-CREATE VIEW vutestv2 AS SELECT * FROM vutest1;
-CREATE VIEW vutestv3 AS SELECT b, a FROM vutest1;
-CREATE VIEW vutestv4 AS SELECT a, b FROM vutest1 WHERE a < 5;
-
--- not updatable tests:
-CREATE VIEW vutestv5 AS SELECT sum(a) FROM vutest1; -- aggregate function
-CREATE VIEW vutestv6 AS SELECT b FROM vutest1 GROUP BY b; -- GROUP BY
-CREATE VIEW vutestv7 AS SELECT l.b AS x, r.b AS y FROM vutest1 l, vutest1 r WHERE r.a = l.a; -- JOIN
-CREATE VIEW vutestv8 AS SELECT 42; -- no table
-CREATE VIEW vutestv9 AS SELECT a * 2 AS x, b || b AS y FROM vutest1; -- derived columns
-CREATE VIEW vutestv10 AS SELECT a AS x, a AS y FROM vutest1; -- column referenced more than once
-CREATE VIEW vutestv11 AS SELECT * FROM generate_series(1, 5); -- table function
-CREATE VIEW vutestv12 AS SELECT xmin, xmax, a, b FROM vutest1; -- system columns
-CREATE VIEW vutestv13 AS SELECT DISTINCT a, b FROM vutest1; -- DISTINCT
-CREATE VIEW vutestv14 AS SELECT a, b FROM vutest1 WHERE a > (SELECT avg(a) FROM vutest1); -- *is* updatable, but SQL standard disallows this
-CREATE VIEW vutestv15 AS SELECT a, b FROM vutest1 UNION ALL SELECT a, b FROM vutest1; -- UNION
-CREATE VIEW vutestv16 AS SELECT x, y FROM (SELECT * FROM vutest1) AS foo (x, y); -- subquery ("derived table"); SQL standard allows this
-CREATE VIEW vutestv17 AS SELECT a, 5, b FROM vutest1; -- constant
-CREATE VIEW vutestv18 AS SELECT a, b FROM vutest1 LIMIT 1; -- LIMIT
-CREATE VIEW vutestv19 AS SELECT a, b FROM vutest1 OFFSET 1; -- OFFSET
-CREATE VIEW vutestv101 AS SELECT a, rank() OVER (PARTITION BY a ORDER BY b DESC) FROM vutest1; -- window function
-CREATE VIEW vutestv102 AS WITH foo AS (SELECT a, b FROM vutest1) SELECT * FROM foo; -- SQL standard allows this
-CREATE VIEW vutestv103 AS WITH RECURSIVE t(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM t) SELECT a FROM vutest1; -- recursive
-
-INSERT INTO vutestv1 VALUES (3, 'three');
-INSERT INTO vutestv2 VALUES (4, 'four');
-INSERT INTO vutestv3 VALUES (5, 'five'); -- fail
-INSERT INTO vutestv3 VALUES ('five', 5);
-INSERT INTO vutestv3 (a, b) VALUES (6, 'six');
-INSERT INTO vutestv4 VALUES (7, 'seven'); -- ok, but would be check option issue
-INSERT INTO vutestv5 VALUES (8); -- fail
-
-SELECT * FROM vutest1;
-SELECT * FROM vutestv1;
-SELECT * FROM vutestv2;
-SELECT * FROM vutestv3;
-SELECT * FROM vutestv4;
-SELECT * FROM vutestv5;
-
-UPDATE vutestv1 SET b = 'a lot' WHERE a = 7;
-DELETE FROM vutestv2 WHERE a = 1;
-UPDATE vutestv4 SET b = b || '!' WHERE a > 1;
-DELETE FROM vutestv4 WHERE a > 3;
-UPDATE vutestv6 SET b = 37; -- fail
-DELETE FROM vutestv5; -- fail
-
-SELECT * FROM vutest1 ORDER BY a, b;
-SELECT * FROM vutestv1 ORDER BY a, b;
-SELECT * FROM vutestv2 ORDER BY a, b;
-SELECT * FROM vutestv4 ORDER BY a, b;
-
-TRUNCATE TABLE vutest1;
-
-
--- views on views
-
-CREATE VIEW vutestv20 AS SELECT a AS x, b AS y FROM vutestv1;
-CREATE VIEW vutestv21 AS SELECT x AS a FROM vutestv20 WHERE x % 2 = 0;
-CREATE VIEW vutestv22 AS SELECT sum(a) FROM vutestv21; -- not updatable
-CREATE VIEW vutestv23 AS SELECT * FROM vutestv12; -- not updatable
-
-INSERT INTO vutestv20 (x, y) VALUES (1, 'one');
-INSERT INTO vutestv20 (x, y) VALUES (3, 'three');
-INSERT INTO vutestv21 VALUES (2);
-
-SELECT * FROM vutest1;
-SELECT * FROM vutestv20;
-SELECT * FROM vutestv21;
-
-UPDATE vutestv20 SET y = 'eins' WHERE x = 1;
-UPDATE vutestv21 SET a = 222;
-
-SELECT * FROM vutest1;
-SELECT * FROM vutestv20;
-SELECT * FROM vutestv21;
-
-DELETE FROM vutestv20 WHERE x = 3;
-
-SELECT * FROM vutest1;
-SELECT * FROM vutestv20;
-SELECT * FROM vutestv21;
-
-
--- insert tests
-
-CREATE TABLE vutest2 (a int PRIMARY KEY, b text NOT NULL, c text NOT NULL DEFAULT 'foo');
-
-CREATE VIEW vutestv30 AS SELECT a, b, c FROM vutest2;
-CREATE VIEW vutestv31 AS SELECT a, b FROM vutest2;
-CREATE VIEW vutestv32 AS SELECT a, c FROM vutest2;
-
-INSERT INTO vutestv30 VALUES (1, 'one', 'eins');
-INSERT INTO vutestv31 VALUES (2, 'two');
-INSERT INTO vutestv32 VALUES (3, 'drei'); -- fail
-
-UPDATE vutestv31 SET a = 22 WHERE a = 2;
-UPDATE vutestv32 SET c = 'drei!' WHERE a = 3;
-
-
-SELECT rulename, definition FROM pg_rules WHERE tablename LIKE 'vutestv%' ORDER BY tablename, rulename;
-
-
--- interaction of manual and automatic rules, view replacement
-
-CREATE VIEW vutestv40 AS SELECT a, b FROM vutest1;
-CREATE RULE zmy_update AS ON UPDATE TO vutestv40 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE RULE "_INSERT" AS ON INSERT TO vutestv40 DO INSTEAD DELETE FROM vutest1; -- replaces automatic _INSERT rule
-CREATE RULE zmy_delete AS ON DELETE TO vutestv40 DO ALSO DELETE FROM vutest1; -- leaves automatic _DELETE rule (because of ALSO)
-
-CREATE VIEW vutestv41 AS SELECT a + 1 AS aa, b FROM vutest1; -- not updatable
-CREATE RULE "_UPDATE" AS ON UPDATE TO vutestv41 DO INSTEAD UPDATE vutest1 SET a = new.aa - 1, b = new.b WHERE a = old.aa - 1 AND b = old.b;
-CREATE OR REPLACE VIEW vutestv41 AS SELECT a AS aa, b FROM vutest1; -- *now* updatable, manual _UPDATE rule stays
-
-CREATE VIEW vutestv42 AS SELECT a + 1 AS aa, b FROM vutest1; -- not updatable
-CREATE RULE zmy_update AS ON UPDATE TO vutestv42 DO INSTEAD UPDATE vutest1 SET a = new.aa - 1, b = new.b WHERE a = old.aa - 1 AND b = old.b;
-CREATE OR REPLACE VIEW vutestv42 AS SELECT a AS aa, b FROM vutest1; -- *now* updatable, zmy_update stays, no _UPDATE created
-
-CREATE VIEW vutestv43 AS SELECT a AS aa, b FROM vutest1; -- updatable
-CREATE RULE zmy_update AS ON UPDATE TO vutestv43 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE OR REPLACE VIEW vutestv43 AS SELECT a + 1 AS aa, b FROM vutest1; -- no longer updatable, automatic rules are deleted, manual rules kept
-
-CREATE VIEW vutestv44 AS SELECT a, b FROM vutest1; -- updatable
-CREATE RULE zmy_update AS ON UPDATE TO vutestv44 DO INSTEAD DELETE FROM vutest1; -- drops automatic _UPDATE rule
-CREATE OR REPLACE VIEW vutestv44 AS SELECT a, b FROM vutest2; -- automatic update rules are updated, manual rules kept
-
-
-SELECT rulename, definition FROM pg_rules WHERE tablename LIKE 'vutestv4_' ORDER BY tablename, rulename;
-
-
--- ACL
-
-CREATE USER regressuser1;
-CREATE USER regressuser2;
-
-GRANT SELECT, INSERT, UPDATE ON vutest1 TO regressuser1;
-
-SET ROLE regressuser1;
-CREATE VIEW vutestv50 AS SELECT a, b FROM vutest1;
-
-GRANT SELECT, UPDATE, DELETE ON vutestv50 TO regressuser2;
-
-SELECT * FROM vutestv50;
-INSERT INTO vutestv50 VALUES (0, 'zero');
-UPDATE vutestv50 SET a = 1;
-UPDATE vutestv50 SET a = 2 WHERE a = 1;
-DELETE FROM vutestv50; -- ERROR
-RESET ROLE;
-
-SET ROLE regressuser2;
-SELECT * FROM vutestv50;
-INSERT INTO vutestv50 VALUES (0, 'zero'); -- ERROR
-UPDATE vutestv50 SET a = 1;
-UPDATE vutestv50 SET a = 2 WHERE a = 1;
-DELETE FROM vutestv50; -- ERROR on vutest1
-RESET ROLE;
-
-DROP VIEW vutestv50;
-
-REVOKE ALL PRIVILEGES ON vutest1 FROM regressuser1;
-DROP USER regressuser1, regressuser2;