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.11 1997/09/08 21:42:50 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/catalog_utils.h>
25 #include <parser/parse_query.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 = tname(get_id_type(res->restype));
77 typename = makeNode(TypeName);
79 typename->name = pstrdup(restypename);
80 def->colname = pstrdup(resname);
82 def->typename = typename;
84 def->is_not_null = false;
85 def->defval = (char *) NULL;
87 attrList = lappend(attrList, def);
92 elog(WARN, "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.archiveType = ARCH_NONE;
104 createStmt.location = -1;
105 createStmt.archiveLoc = -1;
106 createStmt.constraints = NIL;
109 * finally create the relation...
111 DefineRelation(&createStmt);
114 /*------------------------------------------------------------------
115 * makeViewRetrieveRuleName
117 * Given a view name, returns the name for the 'on retrieve to "view"'
119 * This routine is called when defining/removing a view.
121 * NOTE: it quarantees that the name is at most 15 chars long
123 * XXX it also means viewName cannot be 16 chars long! - ay 11/94
124 *------------------------------------------------------------------
127 MakeRetrieveViewRuleName(char *viewName)
132 memset(buf, 0, sizeof(buf));
133 sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
135 namestrcpy(rule_name, buf);
140 buf = palloc(strlen(viewName) + 5);
141 sprintf(buf, "_RET%s", viewName);
146 FormViewRetrieveRule(char *viewName, Query *viewParse)
153 * Create a RuleStmt that corresponds to the suitable rewrite rule
154 * args for DefineQueryRewrite();
156 rule = makeNode(RuleStmt);
157 rname = MakeRetrieveViewRuleName(viewName);
159 attr = makeNode(Attr);
160 attr->relname = pstrdup(viewName);
161 /* attr->refname = pstrdup(viewName);*/
162 rule->rulename = pstrdup(rname);
163 rule->whereClause = NULL;
164 rule->event = CMD_SELECT;
166 rule->instead = true;
167 rule->actions = lcons(viewParse, NIL);
173 DefineViewRules(char *viewName, Query *viewParse)
175 RuleStmt *retrieve_rule = NULL;
178 RuleStmt *replace_rule = NULL;
179 RuleStmt *append_rule = NULL;
180 RuleStmt *delete_rule = NULL;
185 FormViewRetrieveRule(viewName, viewParse);
190 FormViewReplaceRule(viewName, viewParse);
192 FormViewAppendRule(viewName, viewParse);
194 FormViewDeleteRule(viewName, viewParse);
198 DefineQueryRewrite(retrieve_rule);
201 DefineQueryRewrite(replace_rule);
202 DefineQueryRewrite(append_rule);
203 DefineQueryRewrite(delete_rule);
208 /*---------------------------------------------------------------
209 * UpdateRangeTableOfViewParse
211 * Update the range table of the given parsetree.
212 * This update consists of adding two new entries IN THE BEGINNING
213 * of the range table (otherwise the rule system will die a slow,
214 * horrible and painful death, and we do not want that now, do we?)
215 * one for the CURRENT relation and one for the NEW one (both of
216 * them refer in fact to the "view" relation).
218 * Of course we must also increase the 'varnos' of all the Var nodes
221 * NOTE: these are destructive changes. It would be difficult to
222 * make a complete copy of the parse tree and make the changes
224 *---------------------------------------------------------------
227 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
231 RangeTblEntry *rt_entry1,
235 * first offset all var nodes by 2
237 OffsetVarNodes((Node *) viewParse->targetList, 2);
238 OffsetVarNodes(viewParse->qual, 2);
241 * find the old range table...
243 old_rt = viewParse->rtable;
246 * create the 2 new range table entries and form the new range
247 * table... CURRENT first, then NEW....
250 addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
253 addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
255 new_rt = lcons(rt_entry2, old_rt);
256 new_rt = lcons(rt_entry1, new_rt);
259 * Now the tricky part.... Update the range table in place... Be
260 * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
262 viewParse->rtable = new_rt;
265 /*-------------------------------------------------------------------
268 * - takes a "viewname", "parsetree" pair and then
269 * 1) construct the "virtual" relation
270 * 2) commit the command but NOT the transaction,
271 * so that the relation exists
272 * before the rules are defined.
273 * 2) define the "n" rules specified in the PRS2 paper
274 * over the "virtual" relation
275 *-------------------------------------------------------------------
278 DefineView(char *viewName, Query *viewParse)
282 viewTlist = viewParse->targetList;
285 * Create the "view" relation NOTE: if it already exists, the xaxt
288 DefineVirtualRelation(viewName, viewTlist);
291 * The relation we have just created is not visible to any other
292 * commands running with the same transaction & command id. So,
293 * increment the command id counter (but do NOT pfree any memory!!!!)
295 CommandCounterIncrement();
298 * The range table of 'viewParse' does not contain entries for the
299 * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
300 * update in place! After this call 'viewParse' will never be what it
303 UpdateRangeTableOfViewParse(viewName, viewParse);
304 DefineViewRules(viewName, viewParse);
307 /*------------------------------------------------------------------
310 * Remove a view given its name
311 *------------------------------------------------------------------
314 RemoveView(char *viewName)
319 * first remove all the "view" rules... Currently we only have one!
321 rname = MakeRetrieveViewRuleName(viewName);
322 RemoveRewriteRule(rname);
325 * we don't really need that, but just in case...
327 CommandCounterIncrement();
330 * now remove the relation.
332 heap_destroy(viewName);