]> granicus.if.org Git - postgresql/blob - src/backend/commands/view.c
Reimplement parsing and storage of default expressions and constraint
[postgresql] / 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  *      $Id: view.c,v 1.38 1999/10/03 23:55:27 tgl Exp $
9  *
10  *-------------------------------------------------------------------------
11  */
12
13 #include "postgres.h"
14
15 #include "access/xact.h"
16 #include "catalog/heap.h"
17 #include "commands/creatinh.h"
18 #include "commands/view.h"
19 #include "parser/parse_relation.h"
20 #include "parser/parse_type.h"
21 #include "rewrite/rewriteDefine.h"
22 #include "rewrite/rewriteManip.h"
23 #include "rewrite/rewriteRemove.h"
24
25 /*---------------------------------------------------------------------
26  * DefineVirtualRelation
27  *
28  * Create the "view" relation.
29  * `DefineRelation' does all the work, we just provide the correct
30  * arguments!
31  *
32  * If the relation already exists, then 'DefineRelation' will abort
33  * the xact...
34  *---------------------------------------------------------------------
35  */
36 static void
37 DefineVirtualRelation(char *relname, List *tlist)
38 {
39         CreateStmt      createStmt;
40         List       *attrList,
41                            *t;
42         TargetEntry *entry;
43         Resdom     *res;
44         char       *resname;
45         char       *restypename;
46
47         /*
48          * create a list with one entry per attribute of this relation. Each
49          * entry is a two element list. The first element is the name of the
50          * attribute (a string) and the second the name of the type (NOTE: a
51          * string, not a type id!).
52          */
53         attrList = NIL;
54         if (tlist != NIL)
55         {
56                 foreach(t, tlist)
57                 {
58                         ColumnDef  *def = makeNode(ColumnDef);
59                         TypeName   *typename;
60
61                         /*
62                          * find the names of the attribute & its type
63                          */
64                         entry = lfirst(t);
65                         res = entry->resdom;
66                         resname = res->resname;
67                         restypename = typeidTypeName(res->restype);
68
69                         typename = makeNode(TypeName);
70
71                         typename->name = pstrdup(restypename);
72                         typename->typmod = res->restypmod;
73
74                         def->colname = pstrdup(resname);
75
76                         def->typename = typename;
77
78                         def->is_not_null = false;
79                         def->raw_default = NULL;
80                         def->cooked_default = NULL;
81
82                         attrList = lappend(attrList, def);
83                 }
84         }
85         else
86                 elog(ERROR, "attempted to define virtual relation with no attrs");
87
88         /*
89          * now create the parametesr for keys/inheritance etc. All of them are
90          * nil...
91          */
92         createStmt.relname = relname;
93         createStmt.istemp = false;
94         createStmt.tableElts = attrList;
95 /*        createStmt.tableType = NULL;*/
96         createStmt.inhRelnames = NIL;
97         createStmt.constraints = NIL;
98
99         /*
100          * finally create the relation...
101          */
102         DefineRelation(&createStmt, RELKIND_RELATION);
103 }
104
105 /*------------------------------------------------------------------
106  * makeViewRetrieveRuleName
107  *
108  * Given a view name, returns the name for the 'on retrieve to "view"'
109  * rule.
110  * This routine is called when defining/removing a view.
111  *------------------------------------------------------------------
112  */
113 char *
114 MakeRetrieveViewRuleName(char *viewName)
115 {
116         char       *buf;
117
118         buf = palloc(strlen(viewName) + 5);
119         snprintf(buf, strlen(viewName) + 5, "_RET%s", viewName);
120
121         return buf;
122 }
123
124 static RuleStmt *
125 FormViewRetrieveRule(char *viewName, Query *viewParse)
126 {
127         RuleStmt   *rule;
128         char       *rname;
129         Attr       *attr;
130
131         /*
132          * Create a RuleStmt that corresponds to the suitable rewrite rule
133          * args for DefineQueryRewrite();
134          */
135         rule = makeNode(RuleStmt);
136         rname = MakeRetrieveViewRuleName(viewName);
137
138         attr = makeNode(Attr);
139         attr->relname = pstrdup(viewName);
140 /*        attr->refname = pstrdup(viewName);*/
141         rule->rulename = pstrdup(rname);
142         rule->whereClause = NULL;
143         rule->event = CMD_SELECT;
144         rule->object = attr;
145         rule->instead = true;
146         rule->actions = lcons(viewParse, NIL);
147
148         return rule;
149 }
150
151 static void
152 DefineViewRules(char *viewName, Query *viewParse)
153 {
154         RuleStmt   *retrieve_rule = NULL;
155
156 #ifdef NOTYET
157         RuleStmt   *replace_rule = NULL;
158         RuleStmt   *append_rule = NULL;
159         RuleStmt   *delete_rule = NULL;
160
161 #endif
162
163         retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
164
165 #ifdef NOTYET
166
167         replace_rule = FormViewReplaceRule(viewName, viewParse);
168         append_rule = FormViewAppendRule(viewName, viewParse);
169         delete_rule = FormViewDeleteRule(viewName, viewParse);
170
171 #endif
172
173         DefineQueryRewrite(retrieve_rule);
174
175 #ifdef NOTYET
176         DefineQueryRewrite(replace_rule);
177         DefineQueryRewrite(append_rule);
178         DefineQueryRewrite(delete_rule);
179 #endif
180
181 }
182
183 /*---------------------------------------------------------------
184  * UpdateRangeTableOfViewParse
185  *
186  * Update the range table of the given parsetree.
187  * This update consists of adding two new entries IN THE BEGINNING
188  * of the range table (otherwise the rule system will die a slow,
189  * horrible and painful death, and we do not want that now, do we?)
190  * one for the CURRENT relation and one for the NEW one (both of
191  * them refer in fact to the "view" relation).
192  *
193  * Of course we must also increase the 'varnos' of all the Var nodes
194  * by 2...
195  *
196  * NOTE: these are destructive changes. It would be difficult to
197  * make a complete copy of the parse tree and make the changes
198  * in the copy.
199  *---------------------------------------------------------------
200  */
201 static void
202 UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
203 {
204         List       *old_rt;
205         List       *new_rt;
206         RangeTblEntry *rt_entry1,
207                            *rt_entry2;
208
209         /*
210          * first offset all var nodes by 2
211          */
212         OffsetVarNodes((Node *) viewParse->targetList, 2, 0);
213         OffsetVarNodes(viewParse->qual, 2, 0);
214
215         OffsetVarNodes(viewParse->havingQual, 2, 0);
216
217
218         /*
219          * find the old range table...
220          */
221         old_rt = viewParse->rtable;
222
223         /*
224          * create the 2 new range table entries and form the new range
225          * table... CURRENT first, then NEW....
226          */
227         rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
228                                                                    FALSE, FALSE);
229         rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
230                                                                    FALSE, FALSE);
231         new_rt = lcons(rt_entry2, old_rt);
232         new_rt = lcons(rt_entry1, new_rt);
233
234         /*
235          * Now the tricky part.... Update the range table in place... Be
236          * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
237          */
238         viewParse->rtable = new_rt;
239 }
240
241 /*-------------------------------------------------------------------
242  * DefineView
243  *
244  *              - takes a "viewname", "parsetree" pair and then
245  *              1)              construct the "virtual" relation
246  *              2)              commit the command but NOT the transaction,
247  *                              so that the relation exists
248  *                              before the rules are defined.
249  *              2)              define the "n" rules specified in the PRS2 paper
250  *                              over the "virtual" relation
251  *-------------------------------------------------------------------
252  */
253 void
254 DefineView(char *viewName, Query *viewParse)
255 {
256         List       *viewTlist;
257
258         viewTlist = viewParse->targetList;
259
260         /*
261          * Create the "view" relation NOTE: if it already exists, the xaxt
262          * will be aborted.
263          */
264         DefineVirtualRelation(viewName, viewTlist);
265
266         /*
267          * The relation we have just created is not visible to any other
268          * commands running with the same transaction & command id. So,
269          * increment the command id counter (but do NOT pfree any memory!!!!)
270          */
271         CommandCounterIncrement();
272
273         /*
274          * The range table of 'viewParse' does not contain entries for the
275          * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
276          * update in place! After this call 'viewParse' will never be what it
277          * used to be...
278          */
279         UpdateRangeTableOfViewParse(viewName, viewParse);
280         DefineViewRules(viewName, viewParse);
281 }
282
283 /*------------------------------------------------------------------
284  * RemoveView
285  *
286  * Remove a view given its name
287  *------------------------------------------------------------------
288  */
289 void
290 RemoveView(char *viewName)
291 {
292         char       *rname;
293
294         /*
295          * first remove all the "view" rules... Currently we only have one!
296          */
297         rname = MakeRetrieveViewRuleName(viewName);
298         RemoveRewriteRule(rname);
299
300         /*
301          * we don't really need that, but just in case...
302          */
303         CommandCounterIncrement();
304
305         /*
306          * now remove the relation.
307          */
308         heap_destroy_with_catalog(viewName);
309         pfree(rname);
310 }