1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-20 15:22:23 +03:00

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.
This commit is contained in:
Tom Lane
2007-03-13 00:33:44 +00:00
parent f84308f195
commit b9527e9840
61 changed files with 2478 additions and 1354 deletions

View File

@ -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);
}
/*