1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.26 1998/10/21 16:21:22 momjian Exp $
12 *-------------------------------------------------------------------------
14 #include <stdio.h> /* for sprintf() */
19 #include <catalog/heap.h>
20 #include <access/heapam.h>
21 #include <access/xact.h>
22 #include <utils/builtins.h>
23 #include <nodes/relation.h>
24 #include <parser/parse_relation.h>
25 #include <parser/parse_type.h>
26 #include <rewrite/rewriteDefine.h>
27 #include <rewrite/rewriteHandler.h>
28 #include <rewrite/rewriteManip.h>
29 #include <rewrite/rewriteRemove.h>
30 #include <commands/creatinh.h>
31 #include <commands/view.h>
33 /*---------------------------------------------------------------------
34 * DefineVirtualRelation
36 * Create the "view" relation.
37 * `DefineRelation' does all the work, we just provide the correct
40 * If the relation already exists, then 'DefineRelation' will abort
42 *---------------------------------------------------------------------
45 DefineVirtualRelation(char *relname, List *tlist)
47 CreateStmt createStmt;
56 * create a list with one entry per attribute of this relation. Each
57 * entry is a two element list. The first element is the name of the
58 * attribute (a string) and the second the name of the type (NOTE: a
59 * string, not a type id!).
66 ColumnDef *def = makeNode(ColumnDef);
70 * find the names of the attribute & its type
74 resname = res->resname;
75 restypename = typeidTypeName(res->restype);
77 typename = makeNode(TypeName);
79 typename->name = pstrdup(restypename);
80 typename->typmod = res->restypmod;
82 def->colname = pstrdup(resname);
84 def->typename = typename;
86 def->is_not_null = false;
87 def->defval = (char *) NULL;
89 attrList = lappend(attrList, def);
93 elog(ERROR, "attempted to define virtual relation with no attrs");
96 * now create the parametesr for keys/inheritance etc. All of them are
99 createStmt.relname = relname;
100 createStmt.tableElts = attrList;
101 /* createStmt.tableType = NULL;*/
102 createStmt.inhRelnames = NIL;
103 createStmt.constraints = NIL;
106 * finally create the relation...
108 DefineRelation(&createStmt, RELKIND_RELATION);
111 /*------------------------------------------------------------------
112 * makeViewRetrieveRuleName
114 * Given a view name, returns the name for the 'on retrieve to "view"'
116 * This routine is called when defining/removing a view.
117 *------------------------------------------------------------------
120 MakeRetrieveViewRuleName(char *viewName)
124 buf = palloc(strlen(viewName) + 5);
125 sprintf(buf, "_RET%s", viewName);
131 FormViewRetrieveRule(char *viewName, Query *viewParse)
138 * Create a RuleStmt that corresponds to the suitable rewrite rule
139 * args for DefineQueryRewrite();
141 rule = makeNode(RuleStmt);
142 rname = MakeRetrieveViewRuleName(viewName);
144 attr = makeNode(Attr);
145 attr->relname = pstrdup(viewName);
146 /* attr->refname = pstrdup(viewName);*/
147 rule->rulename = pstrdup(rname);
148 rule->whereClause = NULL;
149 rule->event = CMD_SELECT;
151 rule->instead = true;
152 rule->actions = lcons(viewParse, NIL);
158 DefineViewRules(char *viewName, Query *viewParse)
160 RuleStmt *retrieve_rule = NULL;
163 RuleStmt *replace_rule = NULL;
164 RuleStmt *append_rule = NULL;
165 RuleStmt *delete_rule = NULL;
170 FormViewRetrieveRule(viewName, viewParse);
175 FormViewReplaceRule(viewName, viewParse);
177 FormViewAppendRule(viewName, viewParse);
179 FormViewDeleteRule(viewName, viewParse);
183 DefineQueryRewrite(retrieve_rule);
186 DefineQueryRewrite(replace_rule);
187 DefineQueryRewrite(append_rule);
188 DefineQueryRewrite(delete_rule);
193 /*---------------------------------------------------------------
194 * UpdateRangeTableOfViewParse
196 * Update the range table of the given parsetree.
197 * This update consists of adding two new entries IN THE BEGINNING
198 * of the range table (otherwise the rule system will die a slow,
199 * horrible and painful death, and we do not want that now, do we?)
200 * one for the CURRENT relation and one for the NEW one (both of
201 * them refer in fact to the "view" relation).
203 * Of course we must also increase the 'varnos' of all the Var nodes
206 * NOTE: these are destructive changes. It would be difficult to
207 * make a complete copy of the parse tree and make the changes
209 *---------------------------------------------------------------
212 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
216 RangeTblEntry *rt_entry1,
220 * first offset all var nodes by 2
222 OffsetVarNodes((Node *) viewParse->targetList, 2, 0);
223 OffsetVarNodes(viewParse->qual, 2, 0);
225 OffsetVarNodes(viewParse->havingQual, 2, 0);
229 * find the old range table...
231 old_rt = viewParse->rtable;
234 * create the 2 new range table entries and form the new range
235 * table... CURRENT first, then NEW....
238 addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
241 addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
243 new_rt = lcons(rt_entry2, old_rt);
244 new_rt = lcons(rt_entry1, new_rt);
247 * Now the tricky part.... Update the range table in place... Be
248 * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
250 viewParse->rtable = new_rt;
253 /*-------------------------------------------------------------------
256 * - takes a "viewname", "parsetree" pair and then
257 * 1) construct the "virtual" relation
258 * 2) commit the command but NOT the transaction,
259 * so that the relation exists
260 * before the rules are defined.
261 * 2) define the "n" rules specified in the PRS2 paper
262 * over the "virtual" relation
263 *-------------------------------------------------------------------
266 DefineView(char *viewName, Query *viewParse)
270 viewTlist = viewParse->targetList;
273 * Create the "view" relation NOTE: if it already exists, the xaxt
276 DefineVirtualRelation(viewName, viewTlist);
279 * The relation we have just created is not visible to any other
280 * commands running with the same transaction & command id. So,
281 * increment the command id counter (but do NOT pfree any memory!!!!)
283 CommandCounterIncrement();
286 * The range table of 'viewParse' does not contain entries for the
287 * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
288 * update in place! After this call 'viewParse' will never be what it
291 UpdateRangeTableOfViewParse(viewName, viewParse);
292 DefineViewRules(viewName, viewParse);
295 /*------------------------------------------------------------------
298 * Remove a view given its name
299 *------------------------------------------------------------------
302 RemoveView(char *viewName)
307 * first remove all the "view" rules... Currently we only have one!
309 rname = MakeRetrieveViewRuleName(viewName);
310 RemoveRewriteRule(rname);
313 * we don't really need that, but just in case...
315 CommandCounterIncrement();
318 * now remove the relation.
320 heap_destroy_with_catalog(viewName);