1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: view.c,v 1.60 2002/03/22 02:56:31 tgl Exp $
11 *-------------------------------------------------------------------------
15 #include "access/xact.h"
16 #include "catalog/heap.h"
17 #include "commands/creatinh.h"
18 #include "commands/view.h"
19 #include "miscadmin.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"
26 #include "rewrite/rewriteSupport.h"
29 /*---------------------------------------------------------------------
30 * DefineVirtualRelation
32 * Create the "view" relation.
33 * `DefineRelation' does all the work, we just provide the correct
36 * If the relation already exists, then 'DefineRelation' will abort
38 *---------------------------------------------------------------------
41 DefineVirtualRelation(char *relname, List *tlist)
43 CreateStmt *createStmt = makeNode(CreateStmt);
44 RangeVar *rel = makeNode(RangeVar);
49 * create a list of ColumnDef nodes based on the names and types of
50 * the (non-junk) targetlist items from the view's SELECT list.
55 TargetEntry *entry = lfirst(t);
56 Resdom *res = entry->resdom;
60 char *resname = res->resname;
61 char *restypename = typeidTypeName(res->restype);
62 ColumnDef *def = makeNode(ColumnDef);
63 TypeName *typename = makeNode(TypeName);
65 def->colname = pstrdup(resname);
67 typename->name = pstrdup(restypename);
68 typename->typmod = res->restypmod;
69 def->typename = typename;
71 def->is_not_null = false;
72 def->raw_default = NULL;
73 def->cooked_default = NULL;
74 def->constraints = NIL;
76 attrList = lappend(attrList, def);
81 elog(ERROR, "attempted to define virtual relation with no attrs");
84 * now create the parameters for keys/inheritance etc. All of them are
87 rel->relname = relname;
88 rel->schemaname = NULL; /* XXX wrong */
90 createStmt->relation = rel;
91 createStmt->tableElts = attrList;
92 createStmt->inhRelations = NIL;
93 createStmt->constraints = NIL;
94 createStmt->hasoids = false;
97 * finally create the relation...
99 return DefineRelation(createStmt, RELKIND_VIEW);
103 FormViewRetrieveRule(char *viewName, Query *viewParse)
110 * Create a RuleStmt that corresponds to the suitable rewrite rule
111 * args for DefineQueryRewrite();
113 rname = MakeRetrieveViewRuleName(viewName);
115 rel = makeNode(RangeVar);
116 rel->relname = pstrdup(viewName);
117 rel->inhOpt = INH_NO;
120 rule = makeNode(RuleStmt);
121 rule->relation = rel;
122 rule->rulename = pstrdup(rname);
123 rule->whereClause = NULL;
124 rule->event = CMD_SELECT;
125 rule->instead = true;
126 rule->actions = makeList1(viewParse);
132 DefineViewRules(char *viewName, Query *viewParse)
134 RuleStmt *retrieve_rule;
137 RuleStmt *replace_rule;
138 RuleStmt *append_rule;
139 RuleStmt *delete_rule;
142 retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
146 replace_rule = FormViewReplaceRule(viewName, viewParse);
147 append_rule = FormViewAppendRule(viewName, viewParse);
148 delete_rule = FormViewDeleteRule(viewName, viewParse);
151 DefineQueryRewrite(retrieve_rule);
154 DefineQueryRewrite(replace_rule);
155 DefineQueryRewrite(append_rule);
156 DefineQueryRewrite(delete_rule);
161 /*---------------------------------------------------------------
162 * UpdateRangeTableOfViewParse
164 * Update the range table of the given parsetree.
165 * This update consists of adding two new entries IN THE BEGINNING
166 * of the range table (otherwise the rule system will die a slow,
167 * horrible and painful death, and we do not want that now, do we?)
168 * one for the OLD relation and one for the NEW one (both of
169 * them refer in fact to the "view" relation).
171 * Of course we must also increase the 'varnos' of all the Var nodes
174 * These extra RT entries are not actually used in the query,
175 * except for run-time permission checking.
176 *---------------------------------------------------------------
179 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
182 RangeTblEntry *rt_entry1,
186 * Make a copy of the given parsetree. It's not so much that we don't
187 * want to scribble on our input, it's that the parser has a bad habit
188 * of outputting multiple links to the same subtree for constructs
189 * like BETWEEN, and we mustn't have OffsetVarNodes increment the
190 * varno of a Var node twice. copyObject will expand any
191 * multiply-referenced subtree into multiple copies.
193 viewParse = (Query *) copyObject(viewParse);
196 * Create the 2 new range table entries and form the new range
197 * table... OLD first, then NEW....
199 rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
200 makeAlias("*OLD*", NIL),
202 rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
203 makeAlias("*NEW*", NIL),
205 /* Must override addRangeTableEntry's default access-check flags */
206 rt_entry1->checkForRead = false;
207 rt_entry2->checkForRead = false;
209 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
211 viewParse->rtable = new_rt;
214 * Now offset all var nodes by 2, and jointree RT indexes too.
216 OffsetVarNodes((Node *) viewParse, 2, 0);
221 /*-------------------------------------------------------------------
224 * - takes a "viewname", "parsetree" pair and then
225 * 1) construct the "virtual" relation
226 * 2) commit the command but NOT the transaction,
227 * so that the relation exists
228 * before the rules are defined.
229 * 2) define the "n" rules specified in the PRS2 paper
230 * over the "virtual" relation
231 *-------------------------------------------------------------------
234 DefineView(char *viewName, Query *viewParse)
239 * Create the view relation
241 * NOTE: if it already exists, the xact will be aborted.
243 viewOid = DefineVirtualRelation(viewName, viewParse->targetList);
246 * The relation we have just created is not visible to any other
247 * commands running with the same transaction & command id. So,
248 * increment the command id counter (but do NOT pfree any memory!!!!)
250 CommandCounterIncrement();
253 * The range table of 'viewParse' does not contain entries for the
254 * "OLD" and "NEW" relations. So... add them!
256 viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
259 * Now create the rules associated with the view.
261 DefineViewRules(viewName, viewParse);
264 /*------------------------------------------------------------------
267 * Remove a view given its name
268 *------------------------------------------------------------------
271 RemoveView(char *viewName)
274 * We just have to drop the relation; the associated rules will be
275 * cleaned up automatically.
277 heap_drop_with_catalog(viewName, allowSystemTableMods);