OSDN Git Service

A little further progress on schemas: push down RangeVars into
[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-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      $Id: view.c,v 1.60 2002/03/22 02:56:31 tgl Exp $
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 "miscadmin.h"
20 #include "nodes/makefuncs.h"
21 #include "parser/parse_relation.h"
22 #include "parser/parse_type.h"
23 #include "rewrite/rewriteDefine.h"
24 #include "rewrite/rewriteManip.h"
25 #include "rewrite/rewriteRemove.h"
26 #include "rewrite/rewriteSupport.h"
27
28
29 /*---------------------------------------------------------------------
30  * DefineVirtualRelation
31  *
32  * Create the "view" relation.
33  * `DefineRelation' does all the work, we just provide the correct
34  * arguments!
35  *
36  * If the relation already exists, then 'DefineRelation' will abort
37  * the xact...
38  *---------------------------------------------------------------------
39  */
40 static Oid
41 DefineVirtualRelation(char *relname, List *tlist)
42 {
43         CreateStmt *createStmt = makeNode(CreateStmt);
44         RangeVar   *rel = makeNode(RangeVar);
45         List       *attrList,
46                            *t;
47
48         /*
49          * create a list of ColumnDef nodes based on the names and types of
50          * the (non-junk) targetlist items from the view's SELECT list.
51          */
52         attrList = NIL;
53         foreach(t, tlist)
54         {
55                 TargetEntry *entry = lfirst(t);
56                 Resdom     *res = entry->resdom;
57
58                 if (!res->resjunk)
59                 {
60                         char       *resname = res->resname;
61                         char       *restypename = typeidTypeName(res->restype);
62                         ColumnDef  *def = makeNode(ColumnDef);
63                         TypeName   *typename = makeNode(TypeName);
64
65                         def->colname = pstrdup(resname);
66
67                         typename->name = pstrdup(restypename);
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
76                         attrList = lappend(attrList, def);
77                 }
78         }
79
80         if (attrList == NIL)
81                 elog(ERROR, "attempted to define virtual relation with no attrs");
82
83         /*
84          * now create the parameters for keys/inheritance etc. All of them are
85          * nil...
86          */
87         rel->relname = relname;
88         rel->schemaname = NULL;         /* XXX wrong */
89         rel->istemp = false;
90         createStmt->relation = rel;
91         createStmt->tableElts = attrList;
92         createStmt->inhRelations = NIL;
93         createStmt->constraints = NIL;
94         createStmt->hasoids = false;
95
96         /*
97          * finally create the relation...
98          */
99         return DefineRelation(createStmt, RELKIND_VIEW);
100 }
101
102 static RuleStmt *
103 FormViewRetrieveRule(char *viewName, Query *viewParse)
104 {
105         RuleStmt   *rule;
106         char       *rname;
107         RangeVar   *rel;
108
109         /*
110          * Create a RuleStmt that corresponds to the suitable rewrite rule
111          * args for DefineQueryRewrite();
112          */
113         rname = MakeRetrieveViewRuleName(viewName);
114
115         rel = makeNode(RangeVar);
116         rel->relname = pstrdup(viewName);
117         rel->inhOpt = INH_NO;
118         rel->alias = NULL;
119
120         rule = makeNode(RuleStmt);
121         rule->relation = rel;
122         rule->rulename = pstrdup(rname);
123         rule->whereClause = NULL;
124         rule->event = CMD_SELECT;
125         rule->instead = true;
126         rule->actions = makeList1(viewParse);
127
128         return rule;
129 }
130
131 static void
132 DefineViewRules(char *viewName, Query *viewParse)
133 {
134         RuleStmt   *retrieve_rule;
135
136 #ifdef NOTYET
137         RuleStmt   *replace_rule;
138         RuleStmt   *append_rule;
139         RuleStmt   *delete_rule;
140 #endif
141
142         retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
143
144 #ifdef NOTYET
145
146         replace_rule = FormViewReplaceRule(viewName, viewParse);
147         append_rule = FormViewAppendRule(viewName, viewParse);
148         delete_rule = FormViewDeleteRule(viewName, viewParse);
149 #endif
150
151         DefineQueryRewrite(retrieve_rule);
152
153 #ifdef NOTYET
154         DefineQueryRewrite(replace_rule);
155         DefineQueryRewrite(append_rule);
156         DefineQueryRewrite(delete_rule);
157 #endif
158
159 }
160
161 /*---------------------------------------------------------------
162  * UpdateRangeTableOfViewParse
163  *
164  * Update the range table of the given parsetree.
165  * This update consists of adding two new entries IN THE BEGINNING
166  * of the range table (otherwise the rule system will die a slow,
167  * horrible and painful death, and we do not want that now, do we?)
168  * one for the OLD relation and one for the NEW one (both of
169  * them refer in fact to the "view" relation).
170  *
171  * Of course we must also increase the 'varnos' of all the Var nodes
172  * by 2...
173  *
174  * These extra RT entries are not actually used in the query,
175  * except for run-time permission checking.
176  *---------------------------------------------------------------
177  */
178 static Query *
179 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
180 {
181         List       *new_rt;
182         RangeTblEntry *rt_entry1,
183                            *rt_entry2;
184
185         /*
186          * Make a copy of the given parsetree.  It's not so much that we don't
187          * want to scribble on our input, it's that the parser has a bad habit
188          * of outputting multiple links to the same subtree for constructs
189          * like BETWEEN, and we mustn't have OffsetVarNodes increment the
190          * varno of a Var node twice.  copyObject will expand any
191          * multiply-referenced subtree into multiple copies.
192          */
193         viewParse = (Query *) copyObject(viewParse);
194
195         /*
196          * Create the 2 new range table entries and form the new range
197          * table... OLD first, then NEW....
198          */
199         rt_entry1 = addRangeTableEntryForRelation(NULL, viewOid,
200                                                                                           makeAlias("*OLD*", NIL),
201                                                                                           false, false);
202         rt_entry2 = addRangeTableEntryForRelation(NULL, viewOid,
203                                                                                           makeAlias("*NEW*", NIL),
204                                                                                           false, false);
205         /* Must override addRangeTableEntry's default access-check flags */
206         rt_entry1->checkForRead = false;
207         rt_entry2->checkForRead = false;
208
209         new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
210
211         viewParse->rtable = new_rt;
212
213         /*
214          * Now offset all var nodes by 2, and jointree RT indexes too.
215          */
216         OffsetVarNodes((Node *) viewParse, 2, 0);
217
218         return viewParse;
219 }
220
221 /*-------------------------------------------------------------------
222  * DefineView
223  *
224  *              - takes a "viewname", "parsetree" pair and then
225  *              1)              construct the "virtual" relation
226  *              2)              commit the command but NOT the transaction,
227  *                              so that the relation exists
228  *                              before the rules are defined.
229  *              2)              define the "n" rules specified in the PRS2 paper
230  *                              over the "virtual" relation
231  *-------------------------------------------------------------------
232  */
233 void
234 DefineView(char *viewName, Query *viewParse)
235 {
236         Oid                     viewOid;
237
238         /*
239          * Create the view relation
240          *
241          * NOTE: if it already exists, the xact will be aborted.
242          */
243         viewOid = DefineVirtualRelation(viewName, viewParse->targetList);
244
245         /*
246          * The relation we have just created is not visible to any other
247          * commands running with the same transaction & command id. So,
248          * increment the command id counter (but do NOT pfree any memory!!!!)
249          */
250         CommandCounterIncrement();
251
252         /*
253          * The range table of 'viewParse' does not contain entries for the
254          * "OLD" and "NEW" relations. So... add them!
255          */
256         viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
257
258         /*
259          * Now create the rules associated with the view.
260          */
261         DefineViewRules(viewName, viewParse);
262 }
263
264 /*------------------------------------------------------------------
265  * RemoveView
266  *
267  * Remove a view given its name
268  *------------------------------------------------------------------
269  */
270 void
271 RemoveView(char *viewName)
272 {
273         /*
274          * We just have to drop the relation; the associated rules will be
275          * cleaned up automatically.
276          */
277         heap_drop_with_catalog(viewName, allowSystemTableMods);
278 }