OSDN Git Service

Used modified version of indent that understands over 100 typedefs.
[pg-rex/syncrep.git] / src / backend / commands / view.c
1 /*-------------------------------------------------------------------------
2  *
3  * view.c--
4  *        use rewrite rules to construct views
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.11 1997/09/08 21:42:50 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>                              /* for sprintf() */
15 #include <string.h>
16
17 #include <postgres.h>
18
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>
32
33 /*---------------------------------------------------------------------
34  * DefineVirtualRelation
35  *
36  * Create the "view" relation.
37  * `DefineRelation' does all the work, we just provide the correct
38  * arguments!
39  *
40  * If the relation already exists, then 'DefineRelation' will abort
41  * the xact...
42  *---------------------------------------------------------------------
43  */
44 static void
45 DefineVirtualRelation(char *relname, List *tlist)
46 {
47         CreateStmt      createStmt;
48         List       *attrList,
49                            *t;
50         TargetEntry *entry;
51         Resdom     *res;
52         char       *resname;
53         char       *restypename;
54
55         /*
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!).
60          */
61         attrList = NIL;
62         if (tlist != NIL)
63         {
64                 foreach(t, tlist)
65                 {
66                         ColumnDef  *def = makeNode(ColumnDef);
67                         TypeName   *typename;
68
69                         /*
70                          * find the names of the attribute & its type
71                          */
72                         entry = lfirst(t);
73                         res = entry->resdom;
74                         resname = res->resname;
75                         restypename = tname(get_id_type(res->restype));
76
77                         typename = makeNode(TypeName);
78
79                         typename->name = pstrdup(restypename);
80                         def->colname = pstrdup(resname);
81
82                         def->typename = typename;
83
84                         def->is_not_null = false;
85                         def->defval = (char *) NULL;
86
87                         attrList = lappend(attrList, def);
88                 }
89         }
90         else
91         {
92                 elog(WARN, "attempted to define virtual relation with no attrs");
93         }
94
95         /*
96          * now create the parametesr for keys/inheritance etc. All of them are
97          * nil...
98          */
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;
107
108         /*
109          * finally create the relation...
110          */
111         DefineRelation(&createStmt);
112 }
113
114 /*------------------------------------------------------------------
115  * makeViewRetrieveRuleName
116  *
117  * Given a view name, returns the name for the 'on retrieve to "view"'
118  * rule.
119  * This routine is called when defining/removing a view.
120  *
121  * NOTE: it quarantees that the name is at most 15 chars long
122  *
123  * XXX it also means viewName cannot be 16 chars long! - ay 11/94
124  *------------------------------------------------------------------
125  */
126 char       *
127 MakeRetrieveViewRuleName(char *viewName)
128 {
129 /*
130         char buf[100];
131
132         memset(buf, 0, sizeof(buf));
133         sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
134         buf[15] = '\0';
135         namestrcpy(rule_name, buf);
136 */
137
138         char       *buf;
139
140         buf = palloc(strlen(viewName) + 5);
141         sprintf(buf, "_RET%s", viewName);
142         return buf;
143 }
144
145 static RuleStmt *
146 FormViewRetrieveRule(char *viewName, Query *viewParse)
147 {
148         RuleStmt   *rule;
149         char       *rname;
150         Attr       *attr;
151
152         /*
153          * Create a RuleStmt that corresponds to the suitable rewrite rule
154          * args for DefineQueryRewrite();
155          */
156         rule = makeNode(RuleStmt);
157         rname = MakeRetrieveViewRuleName(viewName);
158
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;
165         rule->object = attr;
166         rule->instead = true;
167         rule->actions = lcons(viewParse, NIL);
168
169         return rule;
170 }
171
172 static void
173 DefineViewRules(char *viewName, Query *viewParse)
174 {
175         RuleStmt   *retrieve_rule = NULL;
176
177 #ifdef NOTYET
178         RuleStmt   *replace_rule = NULL;
179         RuleStmt   *append_rule = NULL;
180         RuleStmt   *delete_rule = NULL;
181
182 #endif
183
184         retrieve_rule =
185                 FormViewRetrieveRule(viewName, viewParse);
186
187 #ifdef NOTYET
188
189         replace_rule =
190                 FormViewReplaceRule(viewName, viewParse);
191         append_rule =
192                 FormViewAppendRule(viewName, viewParse);
193         delete_rule =
194                 FormViewDeleteRule(viewName, viewParse);
195
196 #endif
197
198         DefineQueryRewrite(retrieve_rule);
199
200 #ifdef NOTYET
201         DefineQueryRewrite(replace_rule);
202         DefineQueryRewrite(append_rule);
203         DefineQueryRewrite(delete_rule);
204 #endif
205
206 }
207
208 /*---------------------------------------------------------------
209  * UpdateRangeTableOfViewParse
210  *
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).
217  *
218  * Of course we must also increase the 'varnos' of all the Var nodes
219  * by 2...
220  *
221  * NOTE: these are destructive changes. It would be difficult to
222  * make a complete copy of the parse tree and make the changes
223  * in the copy.
224  *---------------------------------------------------------------
225  */
226 static void
227 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
228 {
229         List       *old_rt;
230         List       *new_rt;
231         RangeTblEntry *rt_entry1,
232                            *rt_entry2;
233
234         /*
235          * first offset all var nodes by 2
236          */
237         OffsetVarNodes((Node *) viewParse->targetList, 2);
238         OffsetVarNodes(viewParse->qual, 2);
239
240         /*
241          * find the old range table...
242          */
243         old_rt = viewParse->rtable;
244
245         /*
246          * create the 2 new range table entries and form the new range
247          * table... CURRENT first, then NEW....
248          */
249         rt_entry1 =
250                 addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
251                                                    FALSE, FALSE, NULL);
252         rt_entry2 =
253                 addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
254                                                    FALSE, FALSE, NULL);
255         new_rt = lcons(rt_entry2, old_rt);
256         new_rt = lcons(rt_entry1, new_rt);
257
258         /*
259          * Now the tricky part.... Update the range table in place... Be
260          * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
261          */
262         viewParse->rtable = new_rt;
263 }
264
265 /*-------------------------------------------------------------------
266  * DefineView
267  *
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  *-------------------------------------------------------------------
276  */
277 void
278 DefineView(char *viewName, Query *viewParse)
279 {
280         List       *viewTlist;
281
282         viewTlist = viewParse->targetList;
283
284         /*
285          * Create the "view" relation NOTE: if it already exists, the xaxt
286          * will be aborted.
287          */
288         DefineVirtualRelation(viewName, viewTlist);
289
290         /*
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!!!!)
294          */
295         CommandCounterIncrement();
296
297         /*
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
301          * used to be...
302          */
303         UpdateRangeTableOfViewParse(viewName, viewParse);
304         DefineViewRules(viewName, viewParse);
305 }
306
307 /*------------------------------------------------------------------
308  * RemoveView
309  *
310  * Remove a view given its name
311  *------------------------------------------------------------------
312  */
313 void
314 RemoveView(char *viewName)
315 {
316         char       *rname;
317
318         /*
319          * first remove all the "view" rules... Currently we only have one!
320          */
321         rname = MakeRetrieveViewRuleName(viewName);
322         RemoveRewriteRule(rname);
323
324         /*
325          * we don't really need that, but just in case...
326          */
327         CommandCounterIncrement();
328
329         /*
330          * now remove the relation.
331          */
332         heap_destroy(viewName);
333         pfree(rname);
334 }