OSDN Git Service

1) Queries using the having clause on base tables should work well
[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.23 1998/07/19 05:49:12 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/parse_relation.h>
25 #include <parser/parse_type.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 = typeidTypeName(res->restype);
76
77                         typename = makeNode(TypeName);
78
79                         typename->name = pstrdup(restypename);
80                         typename->typmod = res->restypmod;
81
82                         def->colname = pstrdup(resname);
83
84                         def->typename = typename;
85
86                         def->is_not_null = false;
87                         def->defval = (char *) NULL;
88
89                         attrList = lappend(attrList, def);
90                 }
91         }
92         else
93                 elog(ERROR, "attempted to define virtual relation with no attrs");
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.constraints = NIL;
104
105         /*
106          * finally create the relation...
107          */
108         DefineRelation(&createStmt);
109 }
110
111 /*------------------------------------------------------------------
112  * makeViewRetrieveRuleName
113  *
114  * Given a view name, returns the name for the 'on retrieve to "view"'
115  * rule.
116  * This routine is called when defining/removing a view.
117  *------------------------------------------------------------------
118  */
119 char *
120 MakeRetrieveViewRuleName(char *viewName)
121 {
122         char       *buf;
123
124         buf = palloc(strlen(viewName) + 5);
125         sprintf(buf, "_RET%s", viewName);
126
127         return buf;
128 }
129
130 static RuleStmt *
131 FormViewRetrieveRule(char *viewName, Query *viewParse)
132 {
133         RuleStmt   *rule;
134         char       *rname;
135         Attr       *attr;
136
137         /*
138          * Create a RuleStmt that corresponds to the suitable rewrite rule
139          * args for DefineQueryRewrite();
140          */
141         rule = makeNode(RuleStmt);
142         rname = MakeRetrieveViewRuleName(viewName);
143
144         attr = makeNode(Attr);
145         attr->relname = pstrdup(viewName);
146 /*        attr->refname = pstrdup(viewName);*/
147         rule->rulename = pstrdup(rname);
148         rule->whereClause = NULL;
149         rule->event = CMD_SELECT;
150         rule->object = attr;
151         rule->instead = true;
152         rule->actions = lcons(viewParse, NIL);
153
154         return rule;
155 }
156
157 static void
158 DefineViewRules(char *viewName, Query *viewParse)
159 {
160         RuleStmt   *retrieve_rule = NULL;
161
162 #ifdef NOTYET
163         RuleStmt   *replace_rule = NULL;
164         RuleStmt   *append_rule = NULL;
165         RuleStmt   *delete_rule = NULL;
166
167 #endif
168
169         retrieve_rule =
170                 FormViewRetrieveRule(viewName, viewParse);
171
172 #ifdef NOTYET
173
174         replace_rule =
175                 FormViewReplaceRule(viewName, viewParse);
176         append_rule =
177                 FormViewAppendRule(viewName, viewParse);
178         delete_rule =
179                 FormViewDeleteRule(viewName, viewParse);
180
181 #endif
182
183         DefineQueryRewrite(retrieve_rule);
184
185 #ifdef NOTYET
186         DefineQueryRewrite(replace_rule);
187         DefineQueryRewrite(append_rule);
188         DefineQueryRewrite(delete_rule);
189 #endif
190
191 }
192
193 /*---------------------------------------------------------------
194  * UpdateRangeTableOfViewParse
195  *
196  * Update the range table of the given parsetree.
197  * This update consists of adding two new entries IN THE BEGINNING
198  * of the range table (otherwise the rule system will die a slow,
199  * horrible and painful death, and we do not want that now, do we?)
200  * one for the CURRENT relation and one for the NEW one (both of
201  * them refer in fact to the "view" relation).
202  *
203  * Of course we must also increase the 'varnos' of all the Var nodes
204  * by 2...
205  *
206  * NOTE: these are destructive changes. It would be difficult to
207  * make a complete copy of the parse tree and make the changes
208  * in the copy.
209  *---------------------------------------------------------------
210  */
211 static void
212 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
213 {
214         List       *old_rt;
215         List       *new_rt;
216         RangeTblEntry *rt_entry1,
217                            *rt_entry2;
218
219         /*
220          * first offset all var nodes by 2
221          */
222         OffsetVarNodes((Node *) viewParse->targetList, 2);
223         OffsetVarNodes(viewParse->qual, 2);
224
225         OffsetVarNodes(viewParse->havingQual, 2);
226         
227
228         /*
229          * find the old range table...
230          */
231         old_rt = viewParse->rtable;
232
233         /*
234          * create the 2 new range table entries and form the new range
235          * table... CURRENT first, then NEW....
236          */
237         rt_entry1 =
238                 addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
239                                                    FALSE, FALSE);
240         rt_entry2 =
241                 addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
242                                                    FALSE, FALSE);
243         new_rt = lcons(rt_entry2, old_rt);
244         new_rt = lcons(rt_entry1, new_rt);
245
246         /*
247          * Now the tricky part.... Update the range table in place... Be
248          * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
249          */
250         viewParse->rtable = new_rt;
251 }
252
253 /*-------------------------------------------------------------------
254  * DefineView
255  *
256  *              - takes a "viewname", "parsetree" pair and then
257  *              1)              construct the "virtual" relation
258  *              2)              commit the command but NOT the transaction,
259  *                              so that the relation exists
260  *                              before the rules are defined.
261  *              2)              define the "n" rules specified in the PRS2 paper
262  *                              over the "virtual" relation
263  *-------------------------------------------------------------------
264  */
265 void
266 DefineView(char *viewName, Query *viewParse)
267 {
268         List       *viewTlist;
269
270         viewTlist = viewParse->targetList;
271
272         /*
273          * Create the "view" relation NOTE: if it already exists, the xaxt
274          * will be aborted.
275          */
276         DefineVirtualRelation(viewName, viewTlist);
277
278         /*
279          * The relation we have just created is not visible to any other
280          * commands running with the same transaction & command id. So,
281          * increment the command id counter (but do NOT pfree any memory!!!!)
282          */
283         CommandCounterIncrement();
284
285         /*
286          * The range table of 'viewParse' does not contain entries for the
287          * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
288          * update in place! After this call 'viewParse' will never be what it
289          * used to be...
290          */
291         UpdateRangeTableOfViewParse(viewName, viewParse);
292         DefineViewRules(viewName, viewParse);
293 }
294
295 /*------------------------------------------------------------------
296  * RemoveView
297  *
298  * Remove a view given its name
299  *------------------------------------------------------------------
300  */
301 void
302 RemoveView(char *viewName)
303 {
304         char       *rname;
305
306         /*
307          * first remove all the "view" rules... Currently we only have one!
308          */
309         rname = MakeRetrieveViewRuleName(viewName);
310         RemoveRewriteRule(rname);
311
312         /*
313          * we don't really need that, but just in case...
314          */
315         CommandCounterIncrement();
316
317         /*
318          * now remove the relation.
319          */
320         heap_destroy_with_catalog(viewName);
321         pfree(rname);
322 }