1 /*-------------------------------------------------------------------------
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: view.c,v 1.67 2002/07/16 22:12:19 tgl Exp $
11 *-------------------------------------------------------------------------
15 #include "access/xact.h"
16 #include "catalog/dependency.h"
17 #include "catalog/heap.h"
18 #include "catalog/namespace.h"
19 #include "commands/tablecmds.h"
20 #include "commands/view.h"
21 #include "miscadmin.h"
22 #include "nodes/makefuncs.h"
23 #include "parser/parse_relation.h"
24 #include "parser/parse_type.h"
25 #include "rewrite/rewriteDefine.h"
26 #include "rewrite/rewriteManip.h"
27 #include "rewrite/rewriteRemove.h"
28 #include "rewrite/rewriteSupport.h"
29 #include "utils/syscache.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(const RangeVar *relation, 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 ColumnDef *def = makeNode(ColumnDef);
63 TypeName *typename = makeNode(TypeName);
65 def->colname = pstrdup(res->resname);
67 typename->typeid = res->restype;
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;
77 attrList = lappend(attrList, def);
82 elog(ERROR, "attempted to define virtual relation with no attrs");
85 * now create the parameters for keys/inheritance etc. All of them are
88 createStmt->relation = (RangeVar *) relation;
89 createStmt->tableElts = attrList;
90 createStmt->inhRelations = NIL;
91 createStmt->constraints = NIL;
92 createStmt->hasoids = false;
95 * finally create the relation...
97 return DefineRelation(createStmt, RELKIND_VIEW);
101 FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
106 * Create a RuleStmt that corresponds to the suitable rewrite rule
107 * args for DefineQueryRewrite();
109 rule = makeNode(RuleStmt);
110 rule->relation = copyObject((RangeVar *) view);
111 rule->rulename = pstrdup(ViewSelectRuleName);
112 rule->whereClause = NULL;
113 rule->event = CMD_SELECT;
114 rule->instead = true;
115 rule->actions = makeList1(viewParse);
121 DefineViewRules(const RangeVar *view, Query *viewParse)
123 RuleStmt *retrieve_rule;
126 RuleStmt *replace_rule;
127 RuleStmt *append_rule;
128 RuleStmt *delete_rule;
131 retrieve_rule = FormViewRetrieveRule(view, viewParse);
135 replace_rule = FormViewReplaceRule(view, viewParse);
136 append_rule = FormViewAppendRule(view, viewParse);
137 delete_rule = FormViewDeleteRule(view, viewParse);
140 DefineQueryRewrite(retrieve_rule);
143 DefineQueryRewrite(replace_rule);
144 DefineQueryRewrite(append_rule);
145 DefineQueryRewrite(delete_rule);
150 /*---------------------------------------------------------------
151 * UpdateRangeTableOfViewParse
153 * Update the range table of the given parsetree.
154 * This update consists of adding two new entries IN THE BEGINNING
155 * of the range table (otherwise the rule system will die a slow,
156 * horrible and painful death, and we do not want that now, do we?)
157 * one for the OLD relation and one for the NEW one (both of
158 * them refer in fact to the "view" relation).
160 * Of course we must also increase the 'varnos' of all the Var nodes
163 * These extra RT entries are not actually used in the query,
164 * except for run-time permission checking.
165 *---------------------------------------------------------------
168 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
171 RangeTblEntry *rt_entry1,
175 * Make a copy of the given parsetree. It's not so much that we don't
176 * want to scribble on our input, it's that the parser has a bad habit
177 * of outputting multiple links to the same subtree for constructs
178 * like BETWEEN, and we mustn't have OffsetVarNodes increment the
179 * varno of a Var node twice. copyObject will expand any
180 * multiply-referenced subtree into multiple copies.
182 viewParse = (Query *) copyObject(viewParse);
185 * Create the 2 new range table entries and form the new range
186 * table... OLD first, then NEW....
188 rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
189 makeAlias("*OLD*", NIL),
191 rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
192 makeAlias("*NEW*", NIL),
194 /* Must override addRangeTableEntry's default access-check flags */
195 rt_entry1->checkForRead = false;
196 rt_entry2->checkForRead = false;
198 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
200 viewParse->rtable = new_rt;
203 * Now offset all var nodes by 2, and jointree RT indexes too.
205 OffsetVarNodes((Node *) viewParse, 2, 0);
210 /*-------------------------------------------------------------------
213 * - takes a "viewname", "parsetree" pair and then
214 * 1) construct the "virtual" relation
215 * 2) commit the command but NOT the transaction,
216 * so that the relation exists
217 * before the rules are defined.
218 * 2) define the "n" rules specified in the PRS2 paper
219 * over the "virtual" relation
220 *-------------------------------------------------------------------
223 DefineView(const RangeVar *view, Query *viewParse)
228 * Create the view relation
230 * NOTE: if it already exists, the xact will be aborted.
232 viewOid = DefineVirtualRelation(view, viewParse->targetList);
235 * The relation we have just created is not visible to any other
236 * commands running with the same transaction & command id. So,
237 * increment the command id counter (but do NOT pfree any memory!!!!)
239 CommandCounterIncrement();
242 * The range table of 'viewParse' does not contain entries for the
243 * "OLD" and "NEW" relations. So... add them!
245 viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
248 * Now create the rules associated with the view.
250 DefineViewRules(view, viewParse);
256 * Remove a view given its name
258 * We just have to drop the relation; the associated rules will be
259 * cleaned up automatically.
262 RemoveView(const RangeVar *view, DropBehavior behavior)
265 ObjectAddress object;
267 viewOid = RangeVarGetRelid(view, false);
269 object.classId = RelOid_pg_class;
270 object.objectId = viewOid;
271 object.objectSubId = 0;
273 performDeletion(&object, behavior);