Fix pg_dump bug in the database-level collation patch. "datcollate" and
[PostgreSQL.git] / src / backend / commands / view.c
blobd527d9ef24ac6b29a921a0acd90ea8bde9b2a6b4
1 /*-------------------------------------------------------------------------
3 * view.c
4 * use rewrite rules to construct views
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "access/heapam.h"
18 #include "access/xact.h"
19 #include "catalog/namespace.h"
20 #include "commands/defrem.h"
21 #include "commands/tablecmds.h"
22 #include "commands/view.h"
23 #include "miscadmin.h"
24 #include "nodes/makefuncs.h"
25 #include "nodes/nodeFuncs.h"
26 #include "parser/analyze.h"
27 #include "parser/parse_relation.h"
28 #include "rewrite/rewriteDefine.h"
29 #include "rewrite/rewriteManip.h"
30 #include "rewrite/rewriteSupport.h"
31 #include "utils/acl.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
36 static void checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc);
37 static bool isViewOnTempTable_walker(Node *node, void *context);
39 /*---------------------------------------------------------------------
40 * isViewOnTempTable
42 * Returns true iff any of the relations underlying this view are
43 * temporary tables.
44 *---------------------------------------------------------------------
46 static bool
47 isViewOnTempTable(Query *viewParse)
49 return isViewOnTempTable_walker((Node *) viewParse, NULL);
52 static bool
53 isViewOnTempTable_walker(Node *node, void *context)
55 if (node == NULL)
56 return false;
58 if (IsA(node, Query))
60 Query *query = (Query *) node;
61 ListCell *rtable;
63 foreach(rtable, query->rtable)
65 RangeTblEntry *rte = lfirst(rtable);
67 if (rte->rtekind == RTE_RELATION)
69 Relation rel = heap_open(rte->relid, AccessShareLock);
70 bool istemp = rel->rd_istemp;
72 heap_close(rel, AccessShareLock);
73 if (istemp)
74 return true;
78 return query_tree_walker(query,
79 isViewOnTempTable_walker,
80 context,
81 QTW_IGNORE_JOINALIASES);
84 return expression_tree_walker(node,
85 isViewOnTempTable_walker,
86 context);
89 /*---------------------------------------------------------------------
90 * DefineVirtualRelation
92 * Create the "view" relation. `DefineRelation' does all the work,
93 * we just provide the correct arguments ... at least when we're
94 * creating a view. If we're updating an existing view, we have to
95 * work harder.
96 *---------------------------------------------------------------------
98 static Oid
99 DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
101 Oid viewOid,
102 namespaceId;
103 CreateStmt *createStmt = makeNode(CreateStmt);
104 List *attrList;
105 ListCell *t;
108 * create a list of ColumnDef nodes based on the names and types of the
109 * (non-junk) targetlist items from the view's SELECT list.
111 attrList = NIL;
112 foreach(t, tlist)
114 TargetEntry *tle = lfirst(t);
116 if (!tle->resjunk)
118 ColumnDef *def = makeNode(ColumnDef);
120 def->colname = pstrdup(tle->resname);
121 def->typename = makeTypeNameFromOid(exprType((Node *) tle->expr),
122 exprTypmod((Node *) tle->expr));
123 def->inhcount = 0;
124 def->is_local = true;
125 def->is_not_null = false;
126 def->raw_default = NULL;
127 def->cooked_default = NULL;
128 def->constraints = NIL;
130 attrList = lappend(attrList, def);
134 if (attrList == NIL)
135 ereport(ERROR,
136 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
137 errmsg("view must have at least one column")));
140 * Check to see if we want to replace an existing view.
142 namespaceId = RangeVarGetCreationNamespace(relation);
143 viewOid = get_relname_relid(relation->relname, namespaceId);
145 if (OidIsValid(viewOid) && replace)
147 Relation rel;
148 TupleDesc descriptor;
151 * Yes. Get exclusive lock on the existing view ...
153 rel = relation_open(viewOid, AccessExclusiveLock);
156 * Make sure it *is* a view, and do permissions checks.
158 if (rel->rd_rel->relkind != RELKIND_VIEW)
159 ereport(ERROR,
160 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
161 errmsg("\"%s\" is not a view",
162 RelationGetRelationName(rel))));
164 if (!pg_class_ownercheck(viewOid, GetUserId()))
165 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
166 RelationGetRelationName(rel));
169 * Due to the namespace visibility rules for temporary objects, we
170 * should only end up replacing a temporary view with another
171 * temporary view, and vice versa.
173 Assert(relation->istemp == rel->rd_istemp);
176 * Create a tuple descriptor to compare against the existing view, and
177 * verify it matches.
179 descriptor = BuildDescForRelation(attrList);
180 checkViewTupleDesc(descriptor, rel->rd_att);
183 * Seems okay, so return the OID of the pre-existing view.
185 relation_close(rel, NoLock); /* keep the lock! */
187 return viewOid;
189 else
192 * now set the parameters for keys/inheritance etc. All of these are
193 * uninteresting for views...
195 createStmt->relation = (RangeVar *) relation;
196 createStmt->tableElts = attrList;
197 createStmt->inhRelations = NIL;
198 createStmt->constraints = NIL;
199 createStmt->options = list_make1(defWithOids(false));
200 createStmt->oncommit = ONCOMMIT_NOOP;
201 createStmt->tablespacename = NULL;
204 * finally create the relation (this will error out if there's an
205 * existing view, so we don't need more code to complain if "replace"
206 * is false).
208 return DefineRelation(createStmt, RELKIND_VIEW);
213 * Verify that tupledesc associated with proposed new view definition
214 * matches tupledesc of old view. This is basically a cut-down version
215 * of equalTupleDescs(), with code added to generate specific complaints.
217 static void
218 checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
220 int i;
222 if (newdesc->natts != olddesc->natts)
223 ereport(ERROR,
224 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
225 errmsg("cannot change number of columns in view")));
226 /* we can ignore tdhasoid */
228 for (i = 0; i < newdesc->natts; i++)
230 Form_pg_attribute newattr = newdesc->attrs[i];
231 Form_pg_attribute oldattr = olddesc->attrs[i];
233 /* XXX not right, but we don't support DROP COL on view anyway */
234 if (newattr->attisdropped != oldattr->attisdropped)
235 ereport(ERROR,
236 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
237 errmsg("cannot change number of columns in view")));
239 if (strcmp(NameStr(newattr->attname), NameStr(oldattr->attname)) != 0)
240 ereport(ERROR,
241 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
242 errmsg("cannot change name of view column \"%s\"",
243 NameStr(oldattr->attname))));
244 /* XXX would it be safe to allow atttypmod to change? Not sure */
245 if (newattr->atttypid != oldattr->atttypid ||
246 newattr->atttypmod != oldattr->atttypmod)
247 ereport(ERROR,
248 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
249 errmsg("cannot change data type of view column \"%s\"",
250 NameStr(oldattr->attname))));
251 /* We can ignore the remaining attributes of an attribute... */
255 * We ignore the constraint fields. The new view desc can't have any
256 * constraints, and the only ones that could be on the old view are
257 * defaults, which we are happy to leave in place.
261 static void
262 DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
265 * Set up the ON SELECT rule. Since the query has already been through
266 * parse analysis, we use DefineQueryRewrite() directly.
268 DefineQueryRewrite(pstrdup(ViewSelectRuleName),
269 viewOid,
270 NULL,
271 CMD_SELECT,
272 true,
273 replace,
274 list_make1(viewParse));
277 * Someday: automatic ON INSERT, etc
281 /*---------------------------------------------------------------
282 * UpdateRangeTableOfViewParse
284 * Update the range table of the given parsetree.
285 * This update consists of adding two new entries IN THE BEGINNING
286 * of the range table (otherwise the rule system will die a slow,
287 * horrible and painful death, and we do not want that now, do we?)
288 * one for the OLD relation and one for the NEW one (both of
289 * them refer in fact to the "view" relation).
291 * Of course we must also increase the 'varnos' of all the Var nodes
292 * by 2...
294 * These extra RT entries are not actually used in the query,
295 * except for run-time permission checking.
296 *---------------------------------------------------------------
298 static Query *
299 UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
301 Relation viewRel;
302 List *new_rt;
303 RangeTblEntry *rt_entry1,
304 *rt_entry2;
307 * Make a copy of the given parsetree. It's not so much that we don't
308 * want to scribble on our input, it's that the parser has a bad habit of
309 * outputting multiple links to the same subtree for constructs like
310 * BETWEEN, and we mustn't have OffsetVarNodes increment the varno of a
311 * Var node twice. copyObject will expand any multiply-referenced subtree
312 * into multiple copies.
314 viewParse = (Query *) copyObject(viewParse);
316 /* need to open the rel for addRangeTableEntryForRelation */
317 viewRel = relation_open(viewOid, AccessShareLock);
320 * Create the 2 new range table entries and form the new range table...
321 * OLD first, then NEW....
323 rt_entry1 = addRangeTableEntryForRelation(NULL, viewRel,
324 makeAlias("*OLD*", NIL),
325 false, false);
326 rt_entry2 = addRangeTableEntryForRelation(NULL, viewRel,
327 makeAlias("*NEW*", NIL),
328 false, false);
329 /* Must override addRangeTableEntry's default access-check flags */
330 rt_entry1->requiredPerms = 0;
331 rt_entry2->requiredPerms = 0;
333 new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
335 viewParse->rtable = new_rt;
338 * Now offset all var nodes by 2, and jointree RT indexes too.
340 OffsetVarNodes((Node *) viewParse, 2, 0);
342 relation_close(viewRel, AccessShareLock);
344 return viewParse;
348 * DefineView
349 * Execute a CREATE VIEW command.
351 void
352 DefineView(ViewStmt *stmt, const char *queryString)
354 Query *viewParse;
355 Oid viewOid;
356 RangeVar *view;
359 * Run parse analysis to convert the raw parse tree to a Query. Note this
360 * also acquires sufficient locks on the source table(s).
362 * Since parse analysis scribbles on its input, copy the raw parse tree;
363 * this ensures we don't corrupt a prepared statement, for example.
365 viewParse = parse_analyze((Node *) copyObject(stmt->query),
366 queryString, NULL, 0);
369 * The grammar should ensure that the result is a single SELECT Query.
371 if (!IsA(viewParse, Query) ||
372 viewParse->commandType != CMD_SELECT)
373 elog(ERROR, "unexpected parse analysis result");
376 * If a list of column names was given, run through and insert these into
377 * the actual query tree. - thomas 2000-03-08
379 if (stmt->aliases != NIL)
381 ListCell *alist_item = list_head(stmt->aliases);
382 ListCell *targetList;
384 foreach(targetList, viewParse->targetList)
386 TargetEntry *te = (TargetEntry *) lfirst(targetList);
388 Assert(IsA(te, TargetEntry));
389 /* junk columns don't get aliases */
390 if (te->resjunk)
391 continue;
392 te->resname = pstrdup(strVal(lfirst(alist_item)));
393 alist_item = lnext(alist_item);
394 if (alist_item == NULL)
395 break; /* done assigning aliases */
398 if (alist_item != NULL)
399 ereport(ERROR,
400 (errcode(ERRCODE_SYNTAX_ERROR),
401 errmsg("CREATE VIEW specifies more column "
402 "names than columns")));
406 * If the user didn't explicitly ask for a temporary view, check whether
407 * we need one implicitly. We allow TEMP to be inserted automatically as
408 * long as the CREATE command is consistent with that --- no explicit
409 * schema name.
411 view = stmt->view;
412 if (!view->istemp && isViewOnTempTable(viewParse))
414 view = copyObject(view); /* don't corrupt original command */
415 view->istemp = true;
416 ereport(NOTICE,
417 (errmsg("view \"%s\" will be a temporary view",
418 view->relname)));
422 * Create the view relation
424 * NOTE: if it already exists and replace is false, the xact will be
425 * aborted.
427 viewOid = DefineVirtualRelation(view, viewParse->targetList,
428 stmt->replace);
431 * The relation we have just created is not visible to any other commands
432 * running with the same transaction & command id. So, increment the
433 * command id counter (but do NOT pfree any memory!!!!)
435 CommandCounterIncrement();
438 * The range table of 'viewParse' does not contain entries for the "OLD"
439 * and "NEW" relations. So... add them!
441 viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
444 * Now create the rules associated with the view.
446 DefineViewRules(viewOid, viewParse, stmt->replace);