1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Copyright (c) 1994, Regents of the University of California
8 * $Id: view.c,v 1.37 1999/07/17 20:16:54 momjian Exp $
10 *-------------------------------------------------------------------------
15 #include "access/xact.h"
16 #include "catalog/heap.h"
17 #include "commands/creatinh.h"
18 #include "commands/view.h"
19 #include "parser/parse_relation.h"
20 #include "parser/parse_type.h"
21 #include "rewrite/rewriteDefine.h"
22 #include "rewrite/rewriteManip.h"
23 #include "rewrite/rewriteRemove.h"
25 /*---------------------------------------------------------------------
26 * DefineVirtualRelation
28 * Create the "view" relation.
29 * `DefineRelation' does all the work, we just provide the correct
32 * If the relation already exists, then 'DefineRelation' will abort
34 *---------------------------------------------------------------------
37 DefineVirtualRelation(char *relname, List *tlist)
39 CreateStmt createStmt;
48 * create a list with one entry per attribute of this relation. Each
49 * entry is a two element list. The first element is the name of the
50 * attribute (a string) and the second the name of the type (NOTE: a
51 * string, not a type id!).
58 ColumnDef *def = makeNode(ColumnDef);
62 * find the names of the attribute & its type
66 resname = res->resname;
67 restypename = typeidTypeName(res->restype);
69 typename = makeNode(TypeName);
71 typename->name = pstrdup(restypename);
72 typename->typmod = res->restypmod;
74 def->colname = pstrdup(resname);
76 def->typename = typename;
78 def->is_not_null = false;
79 def->defval = (char *) NULL;
81 attrList = lappend(attrList, def);
85 elog(ERROR, "attempted to define virtual relation with no attrs");
88 * now create the parametesr for keys/inheritance etc. All of them are
91 createStmt.relname = relname;
92 createStmt.istemp = false;
93 createStmt.tableElts = attrList;
94 /* createStmt.tableType = NULL;*/
95 createStmt.inhRelnames = NIL;
96 createStmt.constraints = NIL;
99 * finally create the relation...
101 DefineRelation(&createStmt, RELKIND_RELATION);
104 /*------------------------------------------------------------------
105 * makeViewRetrieveRuleName
107 * Given a view name, returns the name for the 'on retrieve to "view"'
109 * This routine is called when defining/removing a view.
110 *------------------------------------------------------------------
113 MakeRetrieveViewRuleName(char *viewName)
117 buf = palloc(strlen(viewName) + 5);
118 snprintf(buf, strlen(viewName) + 5, "_RET%s", viewName);
124 FormViewRetrieveRule(char *viewName, Query *viewParse)
131 * Create a RuleStmt that corresponds to the suitable rewrite rule
132 * args for DefineQueryRewrite();
134 rule = makeNode(RuleStmt);
135 rname = MakeRetrieveViewRuleName(viewName);
137 attr = makeNode(Attr);
138 attr->relname = pstrdup(viewName);
139 /* attr->refname = pstrdup(viewName);*/
140 rule->rulename = pstrdup(rname);
141 rule->whereClause = NULL;
142 rule->event = CMD_SELECT;
144 rule->instead = true;
145 rule->actions = lcons(viewParse, NIL);
151 DefineViewRules(char *viewName, Query *viewParse)
153 RuleStmt *retrieve_rule = NULL;
156 RuleStmt *replace_rule = NULL;
157 RuleStmt *append_rule = NULL;
158 RuleStmt *delete_rule = NULL;
162 retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
166 replace_rule = FormViewReplaceRule(viewName, viewParse);
167 append_rule = FormViewAppendRule(viewName, viewParse);
168 delete_rule = FormViewDeleteRule(viewName, viewParse);
172 DefineQueryRewrite(retrieve_rule);
175 DefineQueryRewrite(replace_rule);
176 DefineQueryRewrite(append_rule);
177 DefineQueryRewrite(delete_rule);
182 /*---------------------------------------------------------------
183 * UpdateRangeTableOfViewParse
185 * Update the range table of the given parsetree.
186 * This update consists of adding two new entries IN THE BEGINNING
187 * of the range table (otherwise the rule system will die a slow,
188 * horrible and painful death, and we do not want that now, do we?)
189 * one for the CURRENT relation and one for the NEW one (both of
190 * them refer in fact to the "view" relation).
192 * Of course we must also increase the 'varnos' of all the Var nodes
195 * NOTE: these are destructive changes. It would be difficult to
196 * make a complete copy of the parse tree and make the changes
198 *---------------------------------------------------------------
201 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
205 RangeTblEntry *rt_entry1,
209 * first offset all var nodes by 2
211 OffsetVarNodes((Node *) viewParse->targetList, 2, 0);
212 OffsetVarNodes(viewParse->qual, 2, 0);
214 OffsetVarNodes(viewParse->havingQual, 2, 0);
218 * find the old range table...
220 old_rt = viewParse->rtable;
223 * create the 2 new range table entries and form the new range
224 * table... CURRENT first, then NEW....
226 rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
228 rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
230 new_rt = lcons(rt_entry2, old_rt);
231 new_rt = lcons(rt_entry1, new_rt);
234 * Now the tricky part.... Update the range table in place... Be
235 * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
237 viewParse->rtable = new_rt;
240 /*-------------------------------------------------------------------
243 * - takes a "viewname", "parsetree" pair and then
244 * 1) construct the "virtual" relation
245 * 2) commit the command but NOT the transaction,
246 * so that the relation exists
247 * before the rules are defined.
248 * 2) define the "n" rules specified in the PRS2 paper
249 * over the "virtual" relation
250 *-------------------------------------------------------------------
253 DefineView(char *viewName, Query *viewParse)
257 viewTlist = viewParse->targetList;
260 * Create the "view" relation NOTE: if it already exists, the xaxt
263 DefineVirtualRelation(viewName, viewTlist);
266 * The relation we have just created is not visible to any other
267 * commands running with the same transaction & command id. So,
268 * increment the command id counter (but do NOT pfree any memory!!!!)
270 CommandCounterIncrement();
273 * The range table of 'viewParse' does not contain entries for the
274 * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
275 * update in place! After this call 'viewParse' will never be what it
278 UpdateRangeTableOfViewParse(viewName, viewParse);
279 DefineViewRules(viewName, viewParse);
282 /*------------------------------------------------------------------
285 * Remove a view given its name
286 *------------------------------------------------------------------
289 RemoveView(char *viewName)
294 * first remove all the "view" rules... Currently we only have one!
296 rname = MakeRetrieveViewRuleName(viewName);
297 RemoveRewriteRule(rname);
300 * we don't really need that, but just in case...
302 CommandCounterIncrement();
305 * now remove the relation.
307 heap_destroy_with_catalog(viewName);