OSDN Git Service

Add more dependency insertions --- this completes the basic pg_depend
[pg-rex/syncrep.git] / src / backend / commands / view.c
1 /*-------------------------------------------------------------------------
2  *
3  * view.c
4  *        use rewrite rules to construct views
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      $Id: view.c,v 1.67 2002/07/16 22:12:19 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14
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"
30
31
32 /*---------------------------------------------------------------------
33  * DefineVirtualRelation
34  *
35  * Create the "view" relation.
36  * `DefineRelation' does all the work, we just provide the correct
37  * arguments!
38  *
39  * If the relation already exists, then 'DefineRelation' will abort
40  * the xact...
41  *---------------------------------------------------------------------
42  */
43 static Oid
44 DefineVirtualRelation(const RangeVar *relation, List *tlist)
45 {
46         CreateStmt *createStmt = makeNode(CreateStmt);
47         List       *attrList,
48                            *t;
49
50         /*
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.
53          */
54         attrList = NIL;
55         foreach(t, tlist)
56         {
57                 TargetEntry *entry = lfirst(t);
58                 Resdom     *res = entry->resdom;
59
60                 if (!res->resjunk)
61                 {
62                         ColumnDef  *def = makeNode(ColumnDef);
63                         TypeName   *typename = makeNode(TypeName);
64
65                         def->colname = pstrdup(res->resname);
66
67                         typename->typeid = res->restype;
68                         typename->typmod = res->restypmod;
69                         def->typename = typename;
70
71                         def->is_not_null = false;
72                         def->raw_default = NULL;
73                         def->cooked_default = NULL;
74                         def->constraints = NIL;
75                         def->support = NULL;
76
77                         attrList = lappend(attrList, def);
78                 }
79         }
80
81         if (attrList == NIL)
82                 elog(ERROR, "attempted to define virtual relation with no attrs");
83
84         /*
85          * now create the parameters for keys/inheritance etc. All of them are
86          * nil...
87          */
88         createStmt->relation = (RangeVar *) relation;
89         createStmt->tableElts = attrList;
90         createStmt->inhRelations = NIL;
91         createStmt->constraints = NIL;
92         createStmt->hasoids = false;
93
94         /*
95          * finally create the relation...
96          */
97         return DefineRelation(createStmt, RELKIND_VIEW);
98 }
99
100 static RuleStmt *
101 FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
102 {
103         RuleStmt   *rule;
104
105         /*
106          * Create a RuleStmt that corresponds to the suitable rewrite rule
107          * args for DefineQueryRewrite();
108          */
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);
116
117         return rule;
118 }
119
120 static void
121 DefineViewRules(const RangeVar *view, Query *viewParse)
122 {
123         RuleStmt   *retrieve_rule;
124
125 #ifdef NOTYET
126         RuleStmt   *replace_rule;
127         RuleStmt   *append_rule;
128         RuleStmt   *delete_rule;
129 #endif
130
131         retrieve_rule = FormViewRetrieveRule(view, viewParse);
132
133 #ifdef NOTYET
134
135         replace_rule = FormViewReplaceRule(view, viewParse);
136         append_rule = FormViewAppendRule(view, viewParse);
137         delete_rule = FormViewDeleteRule(view, viewParse);
138 #endif
139
140         DefineQueryRewrite(retrieve_rule);
141
142 #ifdef NOTYET
143         DefineQueryRewrite(replace_rule);
144         DefineQueryRewrite(append_rule);
145         DefineQueryRewrite(delete_rule);
146 #endif
147
148 }
149
150 /*---------------------------------------------------------------
151  * UpdateRangeTableOfViewParse
152  *
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).
159  *
160  * Of course we must also increase the 'varnos' of all the Var nodes
161  * by 2...
162  *
163  * These extra RT entries are not actually used in the query,
164  * except for run-time permission checking.
165  *---------------------------------------------------------------
166  */
167 static Query *
168 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
169 {
170         List       *new_rt;
171         RangeTblEntry *rt_entry1,
172                            *rt_entry2;
173
174         /*
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.
181          */
182         viewParse = (Query *) copyObject(viewParse);
183
184         /*
185          * Create the 2 new range table entries and form the new range
186          * table... OLD first, then NEW....
187          */
188         rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
189                                                                                           makeAlias("*OLD*", NIL),
190                                                                                           false, false);
191         rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
192                                                                                           makeAlias("*NEW*", NIL),
193                                                                                           false, false);
194         /* Must override addRangeTableEntry's default access-check flags */
195         rt_entry1->checkForRead = false;
196         rt_entry2->checkForRead = false;
197
198         new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
199
200         viewParse->rtable = new_rt;
201
202         /*
203          * Now offset all var nodes by 2, and jointree RT indexes too.
204          */
205         OffsetVarNodes((Node *) viewParse, 2, 0);
206
207         return viewParse;
208 }
209
210 /*-------------------------------------------------------------------
211  * DefineView
212  *
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  *-------------------------------------------------------------------
221  */
222 void
223 DefineView(const RangeVar *view, Query *viewParse)
224 {
225         Oid                     viewOid;
226
227         /*
228          * Create the view relation
229          *
230          * NOTE: if it already exists, the xact will be aborted.
231          */
232         viewOid = DefineVirtualRelation(view, viewParse->targetList);
233
234         /*
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!!!!)
238          */
239         CommandCounterIncrement();
240
241         /*
242          * The range table of 'viewParse' does not contain entries for the
243          * "OLD" and "NEW" relations. So... add them!
244          */
245         viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
246
247         /*
248          * Now create the rules associated with the view.
249          */
250         DefineViewRules(view, viewParse);
251 }
252
253 /*
254  * RemoveView
255  *
256  * Remove a view given its name
257  *
258  * We just have to drop the relation; the associated rules will be
259  * cleaned up automatically.
260  */
261 void
262 RemoveView(const RangeVar *view, DropBehavior behavior)
263 {
264         Oid                     viewOid;
265         ObjectAddress object;
266
267         viewOid = RangeVarGetRelid(view, false);
268
269         object.classId = RelOid_pg_class;
270         object.objectId = viewOid;
271         object.objectSubId = 0;
272
273         performDeletion(&object, behavior);
274 }