mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
Separate parse-analysis for utility commands out of parser/analyze.c
(which now deals only in optimizable statements), and put that code into a new file parser/parse_utilcmd.c. This helps clarify and enforce the design rule that utility statements shouldn't be processed during the regular parse analysis phase; all interpretation of their meaning should happen after they are given to ProcessUtility to execute. (We need this because we don't retain any locks for a utility statement that's in a plan cache, nor have any way to detect that it's stale.) We are also able to simplify the API for parse_analyze() and related routines, because they will now always return exactly one Query structure. In passing, fix bug #3403 concerning trying to add a serial column to an existing temp table (this is largely Heikki's work, but we needed all that restructuring to make it safe).
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.159 2007/06/03 17:06:16 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.160 2007/06/23 22:12:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -367,7 +367,7 @@ DefineIndex(RangeVar *heapRelation,
|
||||
/*
|
||||
* This shouldn't happen during CREATE TABLE, but can happen
|
||||
* during ALTER TABLE. Keep message in sync with
|
||||
* transformIndexConstraints() in parser/analyze.c.
|
||||
* transformIndexConstraints() in parser/parse_utilcmd.c.
|
||||
*/
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
|
@@ -10,7 +10,7 @@
|
||||
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.76 2007/05/25 17:54:25 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.77 2007/06/23 22:12:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -55,7 +55,6 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
|
||||
{
|
||||
Oid *argtypes = NULL;
|
||||
int nargs;
|
||||
List *queries;
|
||||
Query *query;
|
||||
List *query_list,
|
||||
*plan_list;
|
||||
@@ -105,9 +104,9 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
|
||||
* Because parse analysis scribbles on the raw querytree, we must make
|
||||
* a copy to ensure we have a pristine raw tree to cache. FIXME someday.
|
||||
*/
|
||||
queries = parse_analyze_varparams((Node *) copyObject(stmt->query),
|
||||
queryString,
|
||||
&argtypes, &nargs);
|
||||
query = parse_analyze_varparams((Node *) copyObject(stmt->query),
|
||||
queryString,
|
||||
&argtypes, &nargs);
|
||||
|
||||
/*
|
||||
* Check that all parameter types were determined.
|
||||
@@ -124,15 +123,8 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
|
||||
}
|
||||
|
||||
/*
|
||||
* Shouldn't get any extra statements, since grammar only allows
|
||||
* OptimizableStmt
|
||||
* grammar only allows OptimizableStmt, so this check should be redundant
|
||||
*/
|
||||
if (list_length(queries) != 1)
|
||||
elog(ERROR, "unexpected extra stuff in prepared statement");
|
||||
|
||||
query = (Query *) linitial(queries);
|
||||
Assert(IsA(query, Query));
|
||||
|
||||
switch (query->commandType)
|
||||
{
|
||||
case CMD_SELECT:
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.45 2007/03/23 19:53:51 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.46 2007/06/23 22:12:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/schemacmds.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/analyze.h"
|
||||
#include "parser/parse_utilcmd.h"
|
||||
#include "tcop/utility.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
@@ -111,39 +111,31 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
||||
/*
|
||||
* Examine the list of commands embedded in the CREATE SCHEMA command, and
|
||||
* reorganize them into a sequentially executable order with no forward
|
||||
* references. Note that the result is still a list of raw parsetrees in
|
||||
* need of parse analysis --- we cannot, in general, run analyze.c on one
|
||||
* statement until we have actually executed the prior ones.
|
||||
* references. Note that the result is still a list of raw parsetrees
|
||||
* --- we cannot, in general, run parse analysis on one statement until
|
||||
* we have actually executed the prior ones.
|
||||
*/
|
||||
parsetree_list = analyzeCreateSchemaStmt(stmt);
|
||||
parsetree_list = transformCreateSchemaStmt(stmt);
|
||||
|
||||
/*
|
||||
* Analyze and execute each command contained in the CREATE SCHEMA
|
||||
* Execute each command contained in the CREATE SCHEMA. Since the
|
||||
* grammar allows only utility commands in CREATE SCHEMA, there is
|
||||
* no need to pass them through parse_analyze() or the rewriter;
|
||||
* we can just hand them straight to ProcessUtility.
|
||||
*/
|
||||
foreach(parsetree_item, parsetree_list)
|
||||
{
|
||||
Node *parsetree = (Node *) lfirst(parsetree_item);
|
||||
List *querytree_list;
|
||||
ListCell *querytree_item;
|
||||
Node *stmt = (Node *) lfirst(parsetree_item);
|
||||
|
||||
querytree_list = parse_analyze(parsetree, queryString, NULL, 0);
|
||||
|
||||
foreach(querytree_item, querytree_list)
|
||||
{
|
||||
Query *querytree = (Query *) lfirst(querytree_item);
|
||||
|
||||
/* schemas should contain only utility stmts */
|
||||
Assert(querytree->commandType == CMD_UTILITY);
|
||||
/* do this step */
|
||||
ProcessUtility(querytree->utilityStmt,
|
||||
queryString,
|
||||
NULL,
|
||||
false, /* not top level */
|
||||
None_Receiver,
|
||||
NULL);
|
||||
/* make sure later steps can see the object created here */
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
/* do this step */
|
||||
ProcessUtility(stmt,
|
||||
queryString,
|
||||
NULL,
|
||||
false, /* not top level */
|
||||
None_Receiver,
|
||||
NULL);
|
||||
/* make sure later steps can see the object created here */
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
|
||||
/* Reset search path to normal state */
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.227 2007/06/03 22:16:03 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.228 2007/06/23 22:12:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "parser/analyze.h"
|
||||
#include "parser/gramparse.h"
|
||||
#include "parser/parse_clause.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
@@ -52,6 +51,7 @@
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "parser/parse_utilcmd.h"
|
||||
#include "parser/parser.h"
|
||||
#include "rewrite/rewriteDefine.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
@@ -394,7 +394,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
add_nonduplicate_constraint(cdef, check, &ncheck);
|
||||
}
|
||||
/*
|
||||
* analyze.c might have passed some precooked constraints too,
|
||||
* parse_utilcmd.c might have passed some precooked constraints too,
|
||||
* due to LIKE tab INCLUDING CONSTRAINTS
|
||||
*/
|
||||
foreach(listptr, stmt->constraints)
|
||||
@@ -2922,7 +2922,7 @@ find_composite_type_dependencies(Oid typeOid,
|
||||
*
|
||||
* Adds an additional attribute to a relation making the assumption that
|
||||
* CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
|
||||
* AT_AddColumn AlterTableCmd by analyze.c and added as independent
|
||||
* AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
|
||||
* AlterTableCmd's.
|
||||
*/
|
||||
static void
|
||||
@@ -3745,9 +3745,9 @@ ATExecDropColumn(Relation rel, const char *colName,
|
||||
/*
|
||||
* ALTER TABLE ADD INDEX
|
||||
*
|
||||
* There is no such command in the grammar, but the parser converts UNIQUE
|
||||
* and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets us
|
||||
* schedule creation of the index at the appropriate time during ALTER.
|
||||
* There is no such command in the grammar, but parse_utilcmd.c converts
|
||||
* UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets
|
||||
* us schedule creation of the index at the appropriate time during ALTER.
|
||||
*/
|
||||
static void
|
||||
ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
|
||||
@@ -3766,13 +3766,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
|
||||
/* suppress notices when rebuilding existing index */
|
||||
quiet = is_rebuild;
|
||||
|
||||
/*
|
||||
* Run parse analysis. We don't have convenient access to the query text
|
||||
* here, but it's probably not worth worrying about.
|
||||
*/
|
||||
stmt = analyzeIndexStmt(stmt, NULL);
|
||||
/* The IndexStmt has already been through transformIndexStmt */
|
||||
|
||||
/* ... and do it */
|
||||
DefineIndex(stmt->relation, /* relation */
|
||||
stmt->idxname, /* index name */
|
||||
InvalidOid, /* no predefined OID */
|
||||
@@ -3806,7 +3801,7 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
|
||||
/*
|
||||
* Currently, we only expect to see CONSTR_CHECK nodes
|
||||
* arriving here (see the preprocessing done in
|
||||
* parser/analyze.c). Use a switch anyway to make it easier
|
||||
* parse_utilcmd.c). Use a switch anyway to make it easier
|
||||
* to add more code later.
|
||||
*/
|
||||
switch (constr->contype)
|
||||
@@ -5239,17 +5234,27 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
|
||||
ListCell *list_item;
|
||||
|
||||
/*
|
||||
* We expect that we only have to do raw parsing and parse analysis, not
|
||||
* any rule rewriting, since these will all be utility statements.
|
||||
* We expect that we will get only ALTER TABLE and CREATE INDEX statements.
|
||||
* Hence, there is no need to pass them through parse_analyze() or the
|
||||
* rewriter, but instead we need to pass them through parse_utilcmd.c
|
||||
* to make them ready for execution.
|
||||
*/
|
||||
raw_parsetree_list = raw_parser(cmd);
|
||||
querytree_list = NIL;
|
||||
foreach(list_item, raw_parsetree_list)
|
||||
{
|
||||
Node *parsetree = (Node *) lfirst(list_item);
|
||||
Node *stmt = (Node *) lfirst(list_item);
|
||||
|
||||
querytree_list = list_concat(querytree_list,
|
||||
parse_analyze(parsetree, cmd, NULL, 0));
|
||||
if (IsA(stmt, IndexStmt))
|
||||
querytree_list = lappend(querytree_list,
|
||||
transformIndexStmt((IndexStmt *) stmt,
|
||||
cmd));
|
||||
else if (IsA(stmt, AlterTableStmt))
|
||||
querytree_list = list_concat(querytree_list,
|
||||
transformAlterTableStmt((AlterTableStmt *) stmt,
|
||||
cmd));
|
||||
else
|
||||
querytree_list = lappend(querytree_list, stmt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5258,17 +5263,15 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
|
||||
*/
|
||||
foreach(list_item, querytree_list)
|
||||
{
|
||||
Query *query = (Query *) lfirst(list_item);
|
||||
Node *stm = (Node *) lfirst(list_item);
|
||||
Relation rel;
|
||||
AlteredTableInfo *tab;
|
||||
|
||||
Assert(IsA(query, Query));
|
||||
Assert(query->commandType == CMD_UTILITY);
|
||||
switch (nodeTag(query->utilityStmt))
|
||||
switch (nodeTag(stm))
|
||||
{
|
||||
case T_IndexStmt:
|
||||
{
|
||||
IndexStmt *stmt = (IndexStmt *) query->utilityStmt;
|
||||
IndexStmt *stmt = (IndexStmt *) stm;
|
||||
AlterTableCmd *newcmd;
|
||||
|
||||
rel = relation_openrv(stmt->relation, AccessExclusiveLock);
|
||||
@@ -5283,7 +5286,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
|
||||
}
|
||||
case T_AlterTableStmt:
|
||||
{
|
||||
AlterTableStmt *stmt = (AlterTableStmt *) query->utilityStmt;
|
||||
AlterTableStmt *stmt = (AlterTableStmt *) stm;
|
||||
ListCell *lcmd;
|
||||
|
||||
rel = relation_openrv(stmt->relation, AccessExclusiveLock);
|
||||
@@ -5313,7 +5316,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "unexpected statement type: %d",
|
||||
(int) nodeTag(query->utilityStmt));
|
||||
(int) nodeTag(stm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.100 2007/03/13 00:33:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.101 2007/06/23 22:12:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -351,7 +351,6 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
|
||||
void
|
||||
DefineView(ViewStmt *stmt, const char *queryString)
|
||||
{
|
||||
List *stmts;
|
||||
Query *viewParse;
|
||||
Oid viewOid;
|
||||
RangeVar *view;
|
||||
@@ -363,15 +362,12 @@ DefineView(ViewStmt *stmt, const char *queryString)
|
||||
* 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);
|
||||
viewParse = 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");
|
||||
|
Reference in New Issue
Block a user