aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/view.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-03-13 00:33:44 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-03-13 00:33:44 +0000
commitb9527e984092e838790b543b014c0c2720ea4f11 (patch)
tree60a6063280d446701e1b93e1149eaeb9ce13a128 /src/backend/commands/view.c
parentf84308f1958313f6cd1644d74b6a8ff49a871f8d (diff)
downloadpostgresql-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.c147
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);
}
/*