1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: view.c,v 1.65 2002/07/01 15:27:49 tgl Exp $
11 *-------------------------------------------------------------------------
15 #include "access/xact.h"
16 #include "catalog/heap.h"
17 #include "catalog/namespace.h"
18 #include "commands/tablecmds.h"
19 #include "commands/view.h"
20 #include "miscadmin.h"
21 #include "nodes/makefuncs.h"
22 #include "parser/parse_relation.h"
23 #include "parser/parse_type.h"
24 #include "rewrite/rewriteDefine.h"
25 #include "rewrite/rewriteManip.h"
26 #include "rewrite/rewriteRemove.h"
27 #include "rewrite/rewriteSupport.h"
28 #include "utils/syscache.h"
31 /*---------------------------------------------------------------------
32 * DefineVirtualRelation
34 * Create the "view" relation.
35 * `DefineRelation' does all the work, we just provide the correct
38 * If the relation already exists, then 'DefineRelation' will abort
40 *---------------------------------------------------------------------
43 DefineVirtualRelation(const RangeVar *relation, List *tlist)
45 CreateStmt *createStmt = makeNode(CreateStmt);
50 * create a list of ColumnDef nodes based on the names and types of
51 * the (non-junk) targetlist items from the view's SELECT list.
56 TargetEntry *entry = lfirst(t);
57 Resdom *res = entry->resdom;
61 ColumnDef *def = makeNode(ColumnDef);
62 TypeName *typename = makeNode(TypeName);
64 def->colname = pstrdup(res->resname);
66 typename->typeid = res->restype;
67 typename->typmod = res->restypmod;
68 def->typename = typename;
70 def->is_not_null = false;
71 def->raw_default = NULL;
72 def->cooked_default = NULL;
73 def->constraints = NIL;
75 attrList = lappend(attrList, def);
80 elog(ERROR, "attempted to define virtual relation with no attrs");
83 * now create the parameters for keys/inheritance etc. All of them are
86 createStmt->relation = (RangeVar *) relation;
87 createStmt->tableElts = attrList;
88 createStmt->inhRelations = NIL;
89 createStmt->constraints = NIL;
90 createStmt->hasoids = false;
93 * finally create the relation...
95 return DefineRelation(createStmt, RELKIND_VIEW);
99 FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
104 * Create a RuleStmt that corresponds to the suitable rewrite rule
105 * args for DefineQueryRewrite();
107 rule = makeNode(RuleStmt);
108 rule->relation = copyObject((RangeVar *) view);
109 rule->rulename = pstrdup(ViewSelectRuleName);
110 rule->whereClause = NULL;
111 rule->event = CMD_SELECT;
112 rule->instead = true;
113 rule->actions = makeList1(viewParse);
119 DefineViewRules(const RangeVar *view, Query *viewParse)
121 RuleStmt *retrieve_rule;
124 RuleStmt *replace_rule;
125 RuleStmt *append_rule;
126 RuleStmt *delete_rule;
129 retrieve_rule = FormViewRetrieveRule(view, viewParse);
133 replace_rule = FormViewReplaceRule(view, viewParse);
134 append_rule = FormViewAppendRule(view, viewParse);
135 delete_rule = FormViewDeleteRule(view, viewParse);
138 DefineQueryRewrite(retrieve_rule);
141 DefineQueryRewrite(replace_rule);
142 DefineQueryRewrite(append_rule);
143 DefineQueryRewrite(delete_rule);
148 /*---------------------------------------------------------------
149 * UpdateRangeTableOfViewParse
151 * Update the range table of the given parsetree.
152 * This update consists of adding two new entries IN THE BEGINNING
153 * of the range table (otherwise the rule system will die a slow,
154 * horrible and painful death, and we do not want that now, do we?)
155 * one for the OLD relation and one for the NEW one (both of
156 * them refer in fact to the "view" relation).
158 * Of course we must also increase the 'varnos' of all the Var nodes
161 * These extra RT entries are not actually used in the query,
162 * except for run-time permission checking.
163 *---------------------------------------------------------------
166 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
169 RangeTblEntry *rt_entry1,
173 * Make a copy of the given parsetree. It's not so much that we don't
174 * want to scribble on our input, it's that the parser has a bad habit
175 * of outputting multiple links to the same subtree for constructs
176 * like BETWEEN, and we mustn't have OffsetVarNodes increment the
177 * varno of a Var node twice. copyObject will expand any
178 * multiply-referenced subtree into multiple copies.
180 viewParse = (Query *) copyObject(viewParse);
183 * Create the 2 new range table entries and form the new range
184 * table... OLD first, then NEW....
186 rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
187 makeAlias("*OLD*", NIL),
189 rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
190 makeAlias("*NEW*", NIL),
192 /* Must override addRangeTableEntry's default access-check flags */
193 rt_entry1->checkForRead = false;
194 rt_entry2->checkForRead = false;
196 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
198 viewParse->rtable = new_rt;
201 * Now offset all var nodes by 2, and jointree RT indexes too.
203 OffsetVarNodes((Node *) viewParse, 2, 0);
208 /*-------------------------------------------------------------------
211 * - takes a "viewname", "parsetree" pair and then
212 * 1) construct the "virtual" relation
213 * 2) commit the command but NOT the transaction,
214 * so that the relation exists
215 * before the rules are defined.
216 * 2) define the "n" rules specified in the PRS2 paper
217 * over the "virtual" relation
218 *-------------------------------------------------------------------
221 DefineView(const RangeVar *view, Query *viewParse)
226 * Create the view relation
228 * NOTE: if it already exists, the xact will be aborted.
230 viewOid = DefineVirtualRelation(view, viewParse->targetList);
233 * The relation we have just created is not visible to any other
234 * commands running with the same transaction & command id. So,
235 * increment the command id counter (but do NOT pfree any memory!!!!)
237 CommandCounterIncrement();
240 * The range table of 'viewParse' does not contain entries for the
241 * "OLD" and "NEW" relations. So... add them!
243 viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
246 * Now create the rules associated with the view.
248 DefineViewRules(view, viewParse);
254 * Remove a view given its name
257 RemoveView(const RangeVar *view, DropBehavior behavior)
261 viewOid = RangeVarGetRelid(view, false);
263 * We just have to drop the relation; the associated rules will be
264 * cleaned up automatically.
266 heap_drop_with_catalog(viewOid, allowSystemTableMods);