1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: view.c,v 1.62 2002/04/15 05:22:03 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)
105 * Create a RuleStmt that corresponds to the suitable rewrite rule
106 * args for DefineQueryRewrite();
108 rname = MakeRetrieveViewRuleName(view->relname);
110 rule = makeNode(RuleStmt);
111 rule->relation = copyObject((RangeVar *) view);
112 rule->rulename = pstrdup(rname);
113 rule->whereClause = NULL;
114 rule->event = CMD_SELECT;
115 rule->instead = true;
116 rule->actions = makeList1(viewParse);
122 DefineViewRules(const RangeVar *view, Query *viewParse)
124 RuleStmt *retrieve_rule;
127 RuleStmt *replace_rule;
128 RuleStmt *append_rule;
129 RuleStmt *delete_rule;
132 retrieve_rule = FormViewRetrieveRule(view, viewParse);
136 replace_rule = FormViewReplaceRule(view, viewParse);
137 append_rule = FormViewAppendRule(view, viewParse);
138 delete_rule = FormViewDeleteRule(view, viewParse);
141 DefineQueryRewrite(retrieve_rule);
144 DefineQueryRewrite(replace_rule);
145 DefineQueryRewrite(append_rule);
146 DefineQueryRewrite(delete_rule);
151 /*---------------------------------------------------------------
152 * UpdateRangeTableOfViewParse
154 * Update the range table of the given parsetree.
155 * This update consists of adding two new entries IN THE BEGINNING
156 * of the range table (otherwise the rule system will die a slow,
157 * horrible and painful death, and we do not want that now, do we?)
158 * one for the OLD relation and one for the NEW one (both of
159 * them refer in fact to the "view" relation).
161 * Of course we must also increase the 'varnos' of all the Var nodes
164 * These extra RT entries are not actually used in the query,
165 * except for run-time permission checking.
166 *---------------------------------------------------------------
169 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
172 RangeTblEntry *rt_entry1,
176 * Make a copy of the given parsetree. It's not so much that we don't
177 * want to scribble on our input, it's that the parser has a bad habit
178 * of outputting multiple links to the same subtree for constructs
179 * like BETWEEN, and we mustn't have OffsetVarNodes increment the
180 * varno of a Var node twice. copyObject will expand any
181 * multiply-referenced subtree into multiple copies.
183 viewParse = (Query *) copyObject(viewParse);
186 * Create the 2 new range table entries and form the new range
187 * table... OLD first, then NEW....
189 rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
190 makeAlias("*OLD*", NIL),
192 rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
193 makeAlias("*NEW*", NIL),
195 /* Must override addRangeTableEntry's default access-check flags */
196 rt_entry1->checkForRead = false;
197 rt_entry2->checkForRead = false;
199 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
201 viewParse->rtable = new_rt;
204 * Now offset all var nodes by 2, and jointree RT indexes too.
206 OffsetVarNodes((Node *) viewParse, 2, 0);
211 /*-------------------------------------------------------------------
214 * - takes a "viewname", "parsetree" pair and then
215 * 1) construct the "virtual" relation
216 * 2) commit the command but NOT the transaction,
217 * so that the relation exists
218 * before the rules are defined.
219 * 2) define the "n" rules specified in the PRS2 paper
220 * over the "virtual" relation
221 *-------------------------------------------------------------------
224 DefineView(const RangeVar *view, Query *viewParse)
229 * Create the view relation
231 * NOTE: if it already exists, the xact will be aborted.
233 viewOid = DefineVirtualRelation(view, viewParse->targetList);
236 * The relation we have just created is not visible to any other
237 * commands running with the same transaction & command id. So,
238 * increment the command id counter (but do NOT pfree any memory!!!!)
240 CommandCounterIncrement();
243 * The range table of 'viewParse' does not contain entries for the
244 * "OLD" and "NEW" relations. So... add them!
246 viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
249 * Now create the rules associated with the view.
251 DefineViewRules(view, viewParse);
254 /*------------------------------------------------------------------
257 * Remove a view given its name
258 *------------------------------------------------------------------
261 RemoveView(const RangeVar *view)
265 viewOid = RangeVarGetRelid(view, false);
267 * We just have to drop the relation; the associated rules will be
268 * cleaned up automatically.
270 heap_drop_with_catalog(viewOid, allowSystemTableMods);