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.51 2000/12/21 17:36:15 tgl Exp $
11 *-------------------------------------------------------------------------
16 #include "access/xact.h"
17 #include "catalog/heap.h"
18 #include "commands/creatinh.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"
29 #include "mb/pg_wchar.h"
32 /*---------------------------------------------------------------------
33 * DefineVirtualRelation
35 * Create the "view" relation.
36 * `DefineRelation' does all the work, we just provide the correct
39 * If the relation already exists, then 'DefineRelation' will abort
41 *---------------------------------------------------------------------
44 DefineVirtualRelation(char *relname, List *tlist)
46 CreateStmt *createStmt = makeNode(CreateStmt);
51 * create a list of ColumnDef nodes based on the names and types of
52 * the (non-junk) targetlist items from the view's SELECT list.
57 TargetEntry *entry = lfirst(t);
58 Resdom *res = entry->resdom;
62 char *resname = res->resname;
63 char *restypename = typeidTypeName(res->restype);
64 ColumnDef *def = makeNode(ColumnDef);
65 TypeName *typename = makeNode(TypeName);
67 def->colname = pstrdup(resname);
69 typename->name = pstrdup(restypename);
70 typename->typmod = res->restypmod;
71 def->typename = typename;
73 def->is_not_null = false;
74 def->is_sequence = false;
75 def->raw_default = NULL;
76 def->cooked_default = NULL;
77 def->constraints = NIL;
79 attrList = lappend(attrList, def);
84 elog(ERROR, "attempted to define virtual relation with no attrs");
87 * now create the parameters for keys/inheritance etc. All of them are
90 createStmt->relname = relname;
91 createStmt->istemp = false;
92 createStmt->tableElts = attrList;
93 createStmt->inhRelnames = NIL;
94 createStmt->constraints = NIL;
97 * finally create the relation...
99 DefineRelation(createStmt, RELKIND_VIEW);
102 /*------------------------------------------------------------------
103 * makeViewRetrieveRuleName
105 * Given a view name, returns the name for the 'on retrieve to "view"'
107 *------------------------------------------------------------------
110 MakeRetrieveViewRuleName(char *viewName)
117 buf = palloc(strlen(viewName) + 5);
118 snprintf(buf, strlen(viewName) + 5, "_RET%s", viewName);
121 len = pg_mbcliplen(buf,strlen(buf),NAMEDATALEN-1);
124 buf[NAMEDATALEN-1] = '\0';
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 rule->rulename = pstrdup(rname);
147 rule->whereClause = NULL;
148 rule->event = CMD_SELECT;
150 rule->instead = true;
151 rule->actions = makeList1(viewParse);
157 DefineViewRules(char *viewName, Query *viewParse)
159 RuleStmt *retrieve_rule;
162 RuleStmt *replace_rule;
163 RuleStmt *append_rule;
164 RuleStmt *delete_rule;
168 retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
172 replace_rule = FormViewReplaceRule(viewName, viewParse);
173 append_rule = FormViewAppendRule(viewName, viewParse);
174 delete_rule = FormViewDeleteRule(viewName, viewParse);
178 DefineQueryRewrite(retrieve_rule);
181 DefineQueryRewrite(replace_rule);
182 DefineQueryRewrite(append_rule);
183 DefineQueryRewrite(delete_rule);
188 /*---------------------------------------------------------------
189 * UpdateRangeTableOfViewParse
191 * Update the range table of the given parsetree.
192 * This update consists of adding two new entries IN THE BEGINNING
193 * of the range table (otherwise the rule system will die a slow,
194 * horrible and painful death, and we do not want that now, do we?)
195 * one for the OLD relation and one for the NEW one (both of
196 * them refer in fact to the "view" relation).
198 * Of course we must also increase the 'varnos' of all the Var nodes
201 * These extra RT entries are not actually used in the query,
202 * except for run-time permission checking.
203 *---------------------------------------------------------------
206 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
209 RangeTblEntry *rt_entry1,
213 * Make a copy of the given parsetree. It's not so much that we
214 * don't want to scribble on our input, it's that the parser has
215 * a bad habit of outputting multiple links to the same subtree
216 * for constructs like BETWEEN, and we mustn't have OffsetVarNodes
217 * increment the varno of a Var node twice. copyObject will expand
218 * any multiply-referenced subtree into multiple copies.
220 viewParse = (Query *) copyObject(viewParse);
223 * Create the 2 new range table entries and form the new range
224 * table... OLD first, then NEW....
226 rt_entry1 = addRangeTableEntry(NULL, viewName,
227 makeAttr("*OLD*", NULL),
229 rt_entry2 = addRangeTableEntry(NULL, viewName,
230 makeAttr("*NEW*", NULL),
232 /* Must override addRangeTableEntry's default access-check flags */
233 rt_entry1->checkForRead = false;
234 rt_entry2->checkForRead = false;
236 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
238 viewParse->rtable = new_rt;
241 * Now offset all var nodes by 2, and jointree RT indexes too.
243 OffsetVarNodes((Node *) viewParse, 2, 0);
248 /*-------------------------------------------------------------------
251 * - takes a "viewname", "parsetree" pair and then
252 * 1) construct the "virtual" relation
253 * 2) commit the command but NOT the transaction,
254 * so that the relation exists
255 * before the rules are defined.
256 * 2) define the "n" rules specified in the PRS2 paper
257 * over the "virtual" relation
258 *-------------------------------------------------------------------
261 DefineView(char *viewName, Query *viewParse)
264 * Create the "view" relation NOTE: if it already exists, the xact
267 DefineVirtualRelation(viewName, viewParse->targetList);
270 * The relation we have just created is not visible to any other
271 * commands running with the same transaction & command id. So,
272 * increment the command id counter (but do NOT pfree any memory!!!!)
274 CommandCounterIncrement();
277 * The range table of 'viewParse' does not contain entries for the
278 * "OLD" and "NEW" relations. So... add them!
280 viewParse = UpdateRangeTableOfViewParse(viewName, viewParse);
283 * Now create the rules associated with the view.
285 DefineViewRules(viewName, viewParse);
288 /*------------------------------------------------------------------
291 * Remove a view given its name
292 *------------------------------------------------------------------
295 RemoveView(char *viewName)
298 * We just have to drop the relation; the associated rules will
299 * be cleaned up automatically.
301 heap_drop_with_catalog(viewName, allowSystemTableMods);