1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: view.c,v 1.42 2000/02/15 03:36:39 thomas Exp $
11 *-------------------------------------------------------------------------
16 #include "access/xact.h"
17 #include "catalog/heap.h"
18 #include "commands/creatinh.h"
19 #include "commands/view.h"
20 #include "nodes/makefuncs.h"
21 #include "parser/parse_relation.h"
22 #include "parser/parse_type.h"
23 #include "rewrite/rewriteDefine.h"
24 #include "rewrite/rewriteManip.h"
25 #include "rewrite/rewriteRemove.h"
27 /*---------------------------------------------------------------------
28 * DefineVirtualRelation
30 * Create the "view" relation.
31 * `DefineRelation' does all the work, we just provide the correct
34 * If the relation already exists, then 'DefineRelation' will abort
36 *---------------------------------------------------------------------
39 DefineVirtualRelation(char *relname, List *tlist)
41 CreateStmt createStmt;
50 * create a list with one entry per attribute of this relation. Each
51 * entry is a two element list. The first element is the name of the
52 * attribute (a string) and the second the name of the type (NOTE: a
53 * string, not a type id!).
60 ColumnDef *def = makeNode(ColumnDef);
64 * find the names of the attribute & its type
68 resname = res->resname;
69 restypename = typeidTypeName(res->restype);
71 typename = makeNode(TypeName);
73 typename->name = pstrdup(restypename);
74 typename->typmod = res->restypmod;
76 def->colname = pstrdup(resname);
78 def->typename = typename;
80 def->is_not_null = false;
81 def->raw_default = NULL;
82 def->cooked_default = NULL;
84 attrList = lappend(attrList, def);
88 elog(ERROR, "attempted to define virtual relation with no attrs");
91 * now create the parametesr for keys/inheritance etc. All of them are
94 createStmt.relname = relname;
95 createStmt.istemp = false;
96 createStmt.tableElts = attrList;
97 /* createStmt.tableType = NULL;*/
98 createStmt.inhRelnames = NIL;
99 createStmt.constraints = NIL;
102 * finally create the relation...
104 DefineRelation(&createStmt, RELKIND_RELATION);
107 /*------------------------------------------------------------------
108 * makeViewRetrieveRuleName
110 * Given a view name, returns the name for the 'on retrieve to "view"'
112 * This routine is called when defining/removing a view.
113 *------------------------------------------------------------------
116 MakeRetrieveViewRuleName(char *viewName)
120 buf = palloc(strlen(viewName) + 5);
121 snprintf(buf, strlen(viewName) + 5, "_RET%s", viewName);
127 FormViewRetrieveRule(char *viewName, Query *viewParse)
134 * Create a RuleStmt that corresponds to the suitable rewrite rule
135 * args for DefineQueryRewrite();
137 rule = makeNode(RuleStmt);
138 rname = MakeRetrieveViewRuleName(viewName);
140 attr = makeNode(Attr);
141 attr->relname = pstrdup(viewName);
142 /* attr->refname = pstrdup(viewName);*/
143 rule->rulename = pstrdup(rname);
144 rule->whereClause = NULL;
145 rule->event = CMD_SELECT;
147 rule->instead = true;
148 rule->actions = lcons(viewParse, NIL);
154 DefineViewRules(char *viewName, Query *viewParse)
156 RuleStmt *retrieve_rule = NULL;
159 RuleStmt *replace_rule = NULL;
160 RuleStmt *append_rule = NULL;
161 RuleStmt *delete_rule = NULL;
165 retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
169 replace_rule = FormViewReplaceRule(viewName, viewParse);
170 append_rule = FormViewAppendRule(viewName, viewParse);
171 delete_rule = FormViewDeleteRule(viewName, viewParse);
175 DefineQueryRewrite(retrieve_rule);
178 DefineQueryRewrite(replace_rule);
179 DefineQueryRewrite(append_rule);
180 DefineQueryRewrite(delete_rule);
185 /*---------------------------------------------------------------
186 * UpdateRangeTableOfViewParse
188 * Update the range table of the given parsetree.
189 * This update consists of adding two new entries IN THE BEGINNING
190 * of the range table (otherwise the rule system will die a slow,
191 * horrible and painful death, and we do not want that now, do we?)
192 * one for the CURRENT relation and one for the NEW one (both of
193 * them refer in fact to the "view" relation).
195 * Of course we must also increase the 'varnos' of all the Var nodes
198 * NOTE: these are destructive changes. It would be difficult to
199 * make a complete copy of the parse tree and make the changes
201 *---------------------------------------------------------------
204 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
208 RangeTblEntry *rt_entry1,
212 * first offset all var nodes by 2
214 OffsetVarNodes((Node *) viewParse->targetList, 2, 0);
215 OffsetVarNodes(viewParse->qual, 2, 0);
217 OffsetVarNodes(viewParse->havingQual, 2, 0);
221 * find the old range table...
223 old_rt = viewParse->rtable;
226 * create the 2 new range table entries and form the new range
227 * table... CURRENT first, then NEW....
229 rt_entry1 = addRangeTableEntry(NULL, (char *) viewName,
230 makeAttr("*CURRENT*", NULL),
231 FALSE, FALSE, FALSE);
232 rt_entry2 = addRangeTableEntry(NULL, (char *) viewName,
233 makeAttr("*NEW*", NULL),
234 FALSE, FALSE, FALSE);
235 new_rt = lcons(rt_entry2, old_rt);
236 new_rt = lcons(rt_entry1, new_rt);
239 * Now the tricky part.... Update the range table in place... Be
240 * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
242 viewParse->rtable = new_rt;
245 /*-------------------------------------------------------------------
248 * - takes a "viewname", "parsetree" pair and then
249 * 1) construct the "virtual" relation
250 * 2) commit the command but NOT the transaction,
251 * so that the relation exists
252 * before the rules are defined.
253 * 2) define the "n" rules specified in the PRS2 paper
254 * over the "virtual" relation
255 *-------------------------------------------------------------------
258 DefineView(char *viewName, Query *viewParse)
262 viewTlist = viewParse->targetList;
265 * Create the "view" relation NOTE: if it already exists, the xaxt
268 DefineVirtualRelation(viewName, viewTlist);
271 * The relation we have just created is not visible to any other
272 * commands running with the same transaction & command id. So,
273 * increment the command id counter (but do NOT pfree any memory!!!!)
275 CommandCounterIncrement();
278 * The range table of 'viewParse' does not contain entries for the
279 * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
280 * update in place! After this call 'viewParse' will never be what it
283 UpdateRangeTableOfViewParse(viewName, viewParse);
284 DefineViewRules(viewName, viewParse);
287 /*------------------------------------------------------------------
290 * Remove a view given its name
291 *------------------------------------------------------------------
294 RemoveView(char *viewName)
299 * first remove all the "view" rules... Currently we only have one!
301 rname = MakeRetrieveViewRuleName(viewName);
302 RemoveRewriteRule(rname);
305 * we don't really need that, but just in case...
307 CommandCounterIncrement();
310 * now remove the relation.
312 heap_drop_with_catalog(viewName);