diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-13 00:33:44 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-13 00:33:44 +0000 |
commit | b9527e984092e838790b543b014c0c2720ea4f11 (patch) | |
tree | 60a6063280d446701e1b93e1149eaeb9ce13a128 /src/backend/commands/view.c | |
parent | f84308f1958313f6cd1644d74b6a8ff49a871f8d (diff) | |
download | postgresql-b9527e984092e838790b543b014c0c2720ea4f11.tar.gz postgresql-b9527e984092e838790b543b014c0c2720ea4f11.zip |
First phase of plan-invalidation project: create a plan cache management
module and teach PREPARE and protocol-level prepared statements to use it.
In service of this, rearrange utility-statement processing so that parse
analysis does not assume table schemas can't change before execution for
utility statements (necessary because we don't attempt to re-acquire locks
for utility statements when reusing a stored plan). This requires some
refactoring of the ProcessUtility API, but it ends up cleaner anyway,
for instance we can get rid of the QueryContext global.
Still to do: fix up SPI and related code to use the plan cache; I'm tempted to
try to make SQL functions use it too. Also, there are at least some aspects
of system state that we want to ensure remain the same during a replan as in
the original processing; search_path certainly ought to behave that way for
instance, and perhaps there are others.
Diffstat (limited to 'src/backend/commands/view.c')
-rw-r--r-- | src/backend/commands/view.c | 147 |
1 files changed, 82 insertions, 65 deletions
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 42f9eafd3d2..83f26f73ffb 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.99 2007/01/05 22:19:27 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.100 2007/03/13 00:33:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "miscadmin.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" +#include "parser/analyze.h" #include "parser/parse_expr.h" #include "parser/parse_relation.h" #include "rewrite/rewriteDefine.h" @@ -258,54 +259,23 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) */ } -static RuleStmt * -FormViewRetrieveRule(const RangeVar *view, Query *viewParse, bool replace) -{ - RuleStmt *rule; - - /* - * Create a RuleStmt that corresponds to the suitable rewrite rule args - * for DefineQueryRewrite(); - */ - rule = makeNode(RuleStmt); - rule->relation = copyObject((RangeVar *) view); - rule->rulename = pstrdup(ViewSelectRuleName); - rule->whereClause = NULL; - rule->event = CMD_SELECT; - rule->instead = true; - rule->actions = list_make1(viewParse); - rule->replace = replace; - - return rule; -} - static void DefineViewRules(const RangeVar *view, Query *viewParse, bool replace) { - RuleStmt *retrieve_rule; - -#ifdef NOTYET - RuleStmt *replace_rule; - RuleStmt *append_rule; - RuleStmt *delete_rule; -#endif - - retrieve_rule = FormViewRetrieveRule(view, viewParse, replace); - -#ifdef NOTYET - replace_rule = FormViewReplaceRule(view, viewParse); - append_rule = FormViewAppendRule(view, viewParse); - delete_rule = FormViewDeleteRule(view, viewParse); -#endif - - DefineQueryRewrite(retrieve_rule); - -#ifdef NOTYET - DefineQueryRewrite(replace_rule); - DefineQueryRewrite(append_rule); - DefineQueryRewrite(delete_rule); -#endif - + /* + * Set up the ON SELECT rule. Since the query has already been through + * parse analysis, we use DefineQueryRewrite() directly. + */ + DefineQueryRewrite(pstrdup(ViewSelectRuleName), + (RangeVar *) copyObject((RangeVar *) view), + NULL, + CMD_SELECT, + true, + replace, + list_make1(viewParse)); + /* + * Someday: automatic ON INSERT, etc + */ } /*--------------------------------------------------------------- @@ -374,34 +344,80 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) return viewParse; } -/*------------------------------------------------------------------- +/* * DefineView - * - * - takes a "viewname", "parsetree" pair and then - * 1) construct the "virtual" relation - * 2) commit the command but NOT the transaction, - * so that the relation exists - * before the rules are defined. - * 2) define the "n" rules specified in the PRS2 paper - * over the "virtual" relation - *------------------------------------------------------------------- + * Execute a CREATE VIEW command. */ void -DefineView(RangeVar *view, Query *viewParse, bool replace) +DefineView(ViewStmt *stmt, const char *queryString) { + List *stmts; + Query *viewParse; Oid viewOid; + RangeVar *view; + + /* + * Run parse analysis to convert the raw parse tree to a Query. Note + * this also acquires sufficient locks on the source table(s). + * + * Since parse analysis scribbles on its input, copy the raw parse tree; + * this ensures we don't corrupt a prepared statement, for example. + */ + stmts = parse_analyze((Node *) copyObject(stmt->query), + queryString, NULL, 0); + + /* + * The grammar should ensure that the result is a single SELECT Query. + */ + if (list_length(stmts) != 1) + elog(ERROR, "unexpected parse analysis result"); + viewParse = (Query *) linitial(stmts); + if (!IsA(viewParse, Query) || + viewParse->commandType != CMD_SELECT) + elog(ERROR, "unexpected parse analysis result"); + + /* + * If a list of column names was given, run through and insert these into + * the actual query tree. - thomas 2000-03-08 + */ + if (stmt->aliases != NIL) + { + ListCell *alist_item = list_head(stmt->aliases); + ListCell *targetList; + + foreach(targetList, viewParse->targetList) + { + TargetEntry *te = (TargetEntry *) lfirst(targetList); + + Assert(IsA(te, TargetEntry)); + /* junk columns don't get aliases */ + if (te->resjunk) + continue; + te->resname = pstrdup(strVal(lfirst(alist_item))); + alist_item = lnext(alist_item); + if (alist_item == NULL) + break; /* done assigning aliases */ + } + + if (alist_item != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("CREATE VIEW specifies more column " + "names than columns"))); + } /* * If the user didn't explicitly ask for a temporary view, check whether * we need one implicitly. */ - if (!view->istemp) + view = stmt->view; + if (!view->istemp && isViewOnTempTable(viewParse)) { - view->istemp = isViewOnTempTable(viewParse); - if (view->istemp) - ereport(NOTICE, - (errmsg("view \"%s\" will be a temporary view", - view->relname))); + view = copyObject(view); /* don't corrupt original command */ + view->istemp = true; + ereport(NOTICE, + (errmsg("view \"%s\" will be a temporary view", + view->relname))); } /* @@ -410,7 +426,8 @@ DefineView(RangeVar *view, Query *viewParse, bool replace) * NOTE: if it already exists and replace is false, the xact will be * aborted. */ - viewOid = DefineVirtualRelation(view, viewParse->targetList, replace); + viewOid = DefineVirtualRelation(view, viewParse->targetList, + stmt->replace); /* * The relation we have just created is not visible to any other commands @@ -428,7 +445,7 @@ DefineView(RangeVar *view, Query *viewParse, bool replace) /* * Now create the rules associated with the view. */ - DefineViewRules(view, viewParse, replace); + DefineViewRules(view, viewParse, stmt->replace); } /* |