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:
Tom Lane 2007-06-23 22:12:52 +00:00
parent ec0bb02db8
commit 46379d6e60
23 changed files with 2142 additions and 2095 deletions

View File

@ -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),

View File

@ -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:

View File

@ -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 */

View File

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

View File

@ -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");

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.55 2007/03/17 00:11:03 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.56 2007/06/23 22:12:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -134,6 +134,20 @@ flatCopyTargetEntry(TargetEntry *src_tle)
return tle;
}
/*
* makeFromExpr -
* creates a FromExpr node
*/
FromExpr *
makeFromExpr(List *fromlist, Node *quals)
{
FromExpr *f = makeNode(FromExpr);
f->fromlist = fromlist;
f->quals = quals;
return f;
}
/*
* makeConst -
* creates a Const node

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.246 2007/06/11 01:16:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.247 2007/06/23 22:12:50 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -2910,7 +2910,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
MemoryContext mycxt;
ErrorContextCallback sqlerrcontext;
List *raw_parsetree_list;
List *querytree_list;
Query *querytree;
Node *newexpr;
int *usecounts;
@ -2986,13 +2985,8 @@ inline_function(Oid funcid, Oid result_type, List *args,
if (list_length(raw_parsetree_list) != 1)
goto fail;
querytree_list = parse_analyze(linitial(raw_parsetree_list), src,
argtypes, funcform->pronargs);
if (list_length(querytree_list) != 1)
goto fail;
querytree = (Query *) linitial(querytree_list);
querytree = parse_analyze(linitial(raw_parsetree_list), src,
argtypes, funcform->pronargs);
/*
* The single command must be a simple "SELECT expression".
@ -3025,7 +3019,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
* no rewriting was needed; that's probably not important, but let's be
* careful.
*/
if (check_sql_fn_retval(funcid, result_type, querytree_list, NULL))
if (check_sql_fn_retval(funcid, result_type, list_make1(querytree), NULL))
goto fail; /* reject whole-tuple-result cases */
/*

View File

@ -2,7 +2,7 @@
#
# Makefile for parser
#
# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.44 2006/05/27 17:38:45 tgl Exp $
# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.45 2007/06/23 22:12:51 tgl Exp $
#
#-------------------------------------------------------------------------
@ -14,7 +14,7 @@ override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \
parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
parse_type.o parse_coerce.o parse_target.o scansup.o
parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o
FLEXFLAGS = -CF

View File

@ -1,20 +1,21 @@
This directory does more than tokenize and parse SQL queries. It also
creates Query structures for the various complex queries that is passed
creates Query structures for the various complex queries that are passed
to the optimizer and then executor.
parser.c things start here
scan.l break query into tokens
scansup.c handle escapes in input
scansup.c handle escapes in input strings
keywords.c turn keywords into specific tokens
gram.y parse the tokens and fill query-type-specific structures
analyze.c handle post-parse processing for each query type
analyze.c top level of parse analysis for optimizable queries
parse_clause.c handle clauses like WHERE, ORDER BY, GROUP BY, ...
parse_coerce.c used for coercing expressions of different types
parse_coerce.c handle coercing expressions to different types
parse_expr.c handle expressions like col, col + 3, x = 3 or x = 4
parse_oper.c handle operations in expressions
parse_oper.c handle operators in expressions
parse_agg.c handle aggregates, like SUM(col1), AVG(col2), ...
parse_func.c handle functions, table.column and column identifiers
parse_node.c create nodes for various structures
parse_target.c handle the result list of the query
parse_relation.c support routines for tables and column handling
parse_type.c support routines for type handling
parse_utilcmd.c parse analysis for utility commands (done at execution time)

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.595 2007/06/18 21:40:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.596 2007/06/23 22:12:51 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -33,7 +33,7 @@
* SET SQL_inheritance TO off; SELECT * FROM foo;
* because the entire string is parsed by gram.y before the SET gets
* executed. Anything that depends on the database or changeable state
* should be handled inside parse_analyze() so that it happens at the
* should be handled during parse analysis so that it happens at the
* right time not the wrong time. The handling of SQL_inheritance is
* a good example.
*
@ -2093,9 +2093,10 @@ ColConstraintElem:
* ConstraintAttr represents constraint attributes, which we parse as if
* they were independent constraint clauses, in order to avoid shift/reduce
* conflicts (since NOT might start either an independent NOT NULL clause
* or an attribute). analyze.c is responsible for attaching the attribute
* information to the preceding "real" constraint node, and for complaining
* if attribute clauses appear in the wrong place or wrong combinations.
* or an attribute). parse_utilcmd.c is responsible for attaching the
* attribute information to the preceding "real" constraint node, and for
* complaining if attribute clauses appear in the wrong place or wrong
* combinations.
*
* See also ConstraintAttributeSpec, which can be used in places where
* there is no parsing conflict.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.165 2007/04/27 22:05:48 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.166 2007/06/23 22:12:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -152,8 +152,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Open target rel and grab suitable lock (which we will hold till end of
* transaction).
*
* analyze.c will eventually do the corresponding heap_close(), but *not*
* release the lock.
* free_parsestate() will eventually do the corresponding
* heap_close(), but *not* release the lock.
*/
pstate->p_target_relation = heap_openrv(relation, RowExclusiveLock);
@ -193,7 +193,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
* Simplify InhOption (yes/no/default) into boolean yes/no.
*
* The reason we do things this way is that we don't want to examine the
* SQL_inheritance option flag until parse_analyze is run. Otherwise,
* SQL_inheritance option flag until parse_analyze() is run. Otherwise,
* we'd do the wrong thing with query strings that intermix SET commands
* with queries.
*/
@ -417,7 +417,6 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
static RangeTblEntry *
transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
{
List *parsetrees;
Query *query;
RangeTblEntry *rte;
@ -434,19 +433,12 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
/*
* Analyze and transform the subquery.
*/
parsetrees = parse_sub_analyze(r->subquery, pstate);
query = parse_sub_analyze(r->subquery, pstate);
/*
* Check that we got something reasonable. Most of these conditions are
* probably impossible given restrictions of the grammar, but check 'em
* anyway.
* Check that we got something reasonable. Many of these conditions are
* impossible given restrictions of the grammar, but check 'em anyway.
*/
if (list_length(parsetrees) != 1)
elog(ERROR, "unexpected parse analysis result for subquery in FROM");
query = (Query *) linitial(parsetrees);
if (query == NULL || !IsA(query, Query))
elog(ERROR, "unexpected parse analysis result for subquery in FROM");
if (query->commandType != CMD_SELECT ||
query->utilityStmt != NULL)
elog(ERROR, "expected SELECT query from subquery in FROM");

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.220 2007/06/11 22:22:42 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.221 2007/06/23 22:12:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1120,19 +1120,15 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
static Node *
transformSubLink(ParseState *pstate, SubLink *sublink)
{
List *qtrees;
Query *qtree;
Node *result = (Node *) sublink;
Query *qtree;
/* If we already transformed this node, do nothing */
if (IsA(sublink->subselect, Query))
return result;
pstate->p_hasSubLinks = true;
qtrees = parse_sub_analyze(sublink->subselect, pstate);
if (list_length(qtrees) != 1)
elog(ERROR, "bad query in sub-select");
qtree = (Query *) linitial(qtrees);
qtree = parse_sub_analyze(sublink->subselect, pstate);
if (qtree->commandType != CMD_SELECT ||
qtree->utilityStmt != NULL ||
qtree->intoClause != NULL)

View File

@ -8,12 +8,13 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.97 2007/03/17 00:11:04 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.98 2007/06/23 22:12:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
@ -27,9 +28,11 @@
#include "utils/varbit.h"
/* make_parsestate()
* Allocate and initialize a new ParseState.
* The CALLER is responsible for freeing the ParseState* returned.
/*
* make_parsestate
* Allocate and initialize a new ParseState.
*
* Caller should eventually release the ParseState via free_parsestate().
*/
ParseState *
make_parsestate(ParseState *parentParseState)
@ -52,6 +55,30 @@ make_parsestate(ParseState *parentParseState)
return pstate;
}
/*
* free_parsestate
* Release a ParseState and any subsidiary resources.
*/
void
free_parsestate(ParseState *pstate)
{
/*
* Check that we did not produce too many resnos; at the very least we
* cannot allow more than 2^16, since that would exceed the range of a
* AttrNumber. It seems safest to use MaxTupleAttributeNumber.
*/
if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("target lists can have at most %d entries",
MaxTupleAttributeNumber)));
if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation, NoLock);
pfree(pstate);
}
/*
* parser_errposition

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.120 2007/04/27 22:05:48 tgl Exp $
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.121 2007/06/23 22:12:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,8 +20,8 @@
#include "catalog/pg_rewrite.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/parse_expr.h"
#include "parser/parse_utilcmd.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h"
@ -191,7 +191,7 @@ DefineRule(RuleStmt *stmt, const char *queryString)
Node *whereClause;
/* Parse analysis ... */
analyzeRuleStmt(stmt, queryString, &actions, &whereClause);
transformRuleStmt(stmt, queryString, &actions, &whereClause);
/* ... and execution */
DefineQueryRewrite(stmt->rulename,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.533 2007/04/30 16:37:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.534 2007/06/23 22:12:52 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -165,7 +165,7 @@ static int UseNewLine = 0; /* Use EOF as query delimiters */
static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static List *pg_rewrite_queries(List *querytree_list);
static List *pg_rewrite_query(Query *query);
static bool check_log_statement(List *stmt_list);
static int errdetail_execute(List *raw_parsetree_list);
static int errdetail_params(ParamListInfo params);
@ -567,6 +567,7 @@ List *
pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
Oid *paramTypes, int numParams)
{
Query *query;
List *querytree_list;
/*
@ -575,8 +576,7 @@ pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
if (log_parser_stats)
ResetUsage();
querytree_list = parse_analyze(parsetree, query_string,
paramTypes, numParams);
query = parse_analyze(parsetree, query_string, paramTypes, numParams);
if (log_parser_stats)
ShowUsage("PARSE ANALYSIS STATISTICS");
@ -584,68 +584,55 @@ pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
/*
* (2) Rewrite the queries, as necessary
*/
querytree_list = pg_rewrite_queries(querytree_list);
querytree_list = pg_rewrite_query(query);
return querytree_list;
}
/*
* Perform rewriting of a list of queries produced by parse analysis.
* Perform rewriting of a query produced by parse analysis.
*
* Note: queries must just have come from the parser, because we do not do
* AcquireRewriteLocks() on them.
* Note: query must just have come from the parser, because we do not do
* AcquireRewriteLocks() on it.
*/
static List *
pg_rewrite_queries(List *querytree_list)
pg_rewrite_query(Query *query)
{
List *new_list = NIL;
ListCell *list_item;
List *querytree_list;
if (log_parser_stats)
ResetUsage();
/*
* rewritten queries are collected in new_list. Note there may be more or
* fewer than in the original list.
*/
foreach(list_item, querytree_list)
if (Debug_print_parse)
elog_node_display(DEBUG1, "parse tree", query,
Debug_pretty_print);
if (query->commandType == CMD_UTILITY)
{
Query *querytree = (Query *) lfirst(list_item);
if (Debug_print_parse)
elog_node_display(DEBUG1, "parse tree", querytree,
Debug_pretty_print);
if (querytree->commandType == CMD_UTILITY)
{
/* don't rewrite utilities, just dump 'em into new_list */
new_list = lappend(new_list, querytree);
}
else
{
/* rewrite regular queries */
List *rewritten = QueryRewrite(querytree);
new_list = list_concat(new_list, rewritten);
}
/* don't rewrite utilities, just dump 'em into result list */
querytree_list = list_make1(query);
}
else
{
/* rewrite regular queries */
querytree_list = QueryRewrite(query);
}
querytree_list = new_list;
if (log_parser_stats)
ShowUsage("REWRITER STATISTICS");
#ifdef COPY_PARSE_PLAN_TREES
/* Optional debugging check: pass querytree output through copyObject() */
{
List *new_list;
/*
* Optional debugging check: pass querytree output through copyObject()
*/
new_list = (List *) copyObject(querytree_list);
/* This checks both copyObject() and the equal() routines... */
if (!equal(new_list, querytree_list))
elog(WARNING, "copyObject() failed to produce an equal parse tree");
else
querytree_list = new_list;
new_list = (List *) copyObject(querytree_list);
/* This checks both copyObject() and the equal() routines... */
if (!equal(new_list, querytree_list))
elog(WARNING, "copyObject() failed to produce equal parse tree");
else
querytree_list = new_list;
}
#endif
if (Debug_print_rewritten)
@ -1139,6 +1126,7 @@ exec_parse_message(const char *query_string, /* string to execute */
if (parsetree_list != NIL)
{
Query *query;
int i;
raw_parse_tree = (Node *) linitial(parsetree_list);
@ -1175,10 +1163,10 @@ exec_parse_message(const char *query_string, /* string to execute */
if (log_parser_stats)
ResetUsage();
querytree_list = parse_analyze_varparams(copyObject(raw_parse_tree),
query_string,
&paramTypes,
&numParams);
query = parse_analyze_varparams(copyObject(raw_parse_tree),
query_string,
&paramTypes,
&numParams);
/*
* Check all parameter types got determined.
@ -1197,7 +1185,7 @@ exec_parse_message(const char *query_string, /* string to execute */
if (log_parser_stats)
ShowUsage("PARSE ANALYSIS STATISTICS");
querytree_list = pg_rewrite_queries(querytree_list);
querytree_list = pg_rewrite_query(query);
/*
* If this is the unnamed statement and it has parameters, defer query

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.280 2007/05/30 20:12:01 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.281 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,7 +45,7 @@
#include "commands/vacuum.h"
#include "commands/view.h"
#include "miscadmin.h"
#include "parser/analyze.h"
#include "parser/parse_utilcmd.h"
#include "postmaster/bgwriter.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
@ -544,17 +544,47 @@ ProcessUtility(Node *parsetree,
case T_CreateStmt:
{
List *stmts;
ListCell *l;
Oid relOid;
relOid = DefineRelation((CreateStmt *) parsetree,
RELKIND_RELATION);
/* Run parse analysis ... */
stmts = transformCreateStmt((CreateStmt *) parsetree,
queryString);
/*
* Let AlterTableCreateToastTable decide if this one needs a
* secondary relation too.
*/
CommandCounterIncrement();
AlterTableCreateToastTable(relOid);
/* ... and do it */
foreach(l, stmts)
{
Node *stmt = (Node *) lfirst(l);
if (IsA(stmt, CreateStmt))
{
/* Create the table itself */
relOid = DefineRelation((CreateStmt *) stmt,
RELKIND_RELATION);
/*
* Let AlterTableCreateToastTable decide if this one
* needs a secondary relation too.
*/
CommandCounterIncrement();
AlterTableCreateToastTable(relOid);
}
else
{
/* Recurse for anything else */
ProcessUtility(stmt,
queryString,
params,
false,
None_Receiver,
NULL);
}
/* Need CCI between commands */
if (lnext(l) != NULL)
CommandCounterIncrement();
}
}
break;
@ -693,7 +723,40 @@ ProcessUtility(Node *parsetree,
break;
case T_AlterTableStmt:
AlterTable((AlterTableStmt *) parsetree);
{
List *stmts;
ListCell *l;
/* Run parse analysis ... */
stmts = transformAlterTableStmt((AlterTableStmt *) parsetree,
queryString);
/* ... and do it */
foreach(l, stmts)
{
Node *stmt = (Node *) lfirst(l);
if (IsA(stmt, AlterTableStmt))
{
/* Do the table alteration proper */
AlterTable((AlterTableStmt *) stmt);
}
else
{
/* Recurse for anything else */
ProcessUtility(stmt,
queryString,
params,
false,
None_Receiver,
NULL);
}
/* Need CCI between commands */
if (lnext(l) != NULL)
CommandCounterIncrement();
}
}
break;
case T_AlterDomainStmt:
@ -812,7 +875,7 @@ ProcessUtility(Node *parsetree,
CheckRelationOwnership(stmt->relation, true);
/* Run parse analysis ... */
stmt = analyzeIndexStmt(stmt, queryString);
stmt = transformIndexStmt(stmt, queryString);
/* ... and do it */
DefineIndex(stmt->relation, /* relation */
@ -1605,7 +1668,7 @@ CreateCommandTag(Node *parsetree)
/*
* We might be supporting ALTER INDEX here, so set the
* completion table appropriately. Catch all other
* completion tag appropriately. Catch all other
* possibilities with ALTER TABLE
*/

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.58 2007/03/17 00:11:05 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.59 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -36,6 +36,8 @@ extern TargetEntry *makeTargetEntry(Expr *expr,
extern TargetEntry *flatCopyTargetEntry(TargetEntry *src_tle);
extern FromExpr *makeFromExpr(List *fromlist, Node *quals);
extern Const *makeConst(Oid consttype,
int32 consttypmod,
int constlen,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.348 2007/04/27 22:05:49 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.349 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,7 +21,7 @@
typedef enum QuerySource
{
QSRC_ORIGINAL, /* original parsetree (explicit query) */
QSRC_PARSER, /* added by parse analysis */
QSRC_PARSER, /* added by parse analysis (now unused) */
QSRC_INSTEAD_RULE, /* added by unconditional INSTEAD rule */
QSRC_QUAL_INSTEAD_RULE, /* added by conditional INSTEAD rule */
QSRC_NON_INSTEAD_RULE /* added by non-INSTEAD rule */
@ -799,10 +799,12 @@ typedef struct SetOperationStmt
/*****************************************************************************
* Other Statements (no optimizations required)
*
* Some of them require a little bit of transformation (which is also
* done by transformStmt). The whole structure is then passed on to
* ProcessUtility (by-passing the optimization step) as the utilityStmt
* field in Query.
* These are not touched by parser/analyze.c except to put them into
* the utilityStmt field of a Query. This is eventually passed to
* ProcessUtility (by-passing rewriting and planning). Some of the
* statements do need attention from parse analysis, and this is
* done by routines in parser/parse_utilcmd.c after ProcessUtility
* receives the command for execution.
*****************************************************************************/
/*
@ -886,7 +888,7 @@ typedef enum AlterTableType
AT_ReAddIndex, /* internal to commands/tablecmds.c */
AT_AddConstraint, /* add constraint */
AT_ProcessedConstraint, /* pre-processed add constraint (local in
* parser/analyze.c) */
* parser/parse_utilcmd.c) */
AT_DropConstraint, /* drop constraint */
AT_DropConstraintQuietly, /* drop constraint, no error/warning (local in
* commands/tablecmds.c) */
@ -1083,7 +1085,7 @@ typedef struct CreateStmt
* relation). We should never have both in the same node!
*
* Constraint attributes (DEFERRABLE etc) are initially represented as
* separate Constraint nodes for simplicity of parsing. analyze.c makes
* separate Constraint nodes for simplicity of parsing. parse_utilcmd.c makes
* a pass through the constraints list to attach the info to the appropriate
* FkConstraint node (and, perhaps, someday to other kinds of constraints).
* ----------

View File

@ -1,12 +1,13 @@
/*-------------------------------------------------------------------------
*
* analyze.h
* parse analysis for optimizable statements
*
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.36 2007/03/13 00:33:43 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.37 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,16 +17,14 @@
#include "parser/parse_node.h"
extern List *parse_analyze(Node *parseTree, const char *sourceText,
extern Query *parse_analyze(Node *parseTree, const char *sourceText,
Oid *paramTypes, int numParams);
extern List *parse_analyze_varparams(Node *parseTree, const char *sourceText,
extern Query *parse_analyze_varparams(Node *parseTree, const char *sourceText,
Oid **paramTypes, int *numParams);
extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
extern IndexStmt *analyzeIndexStmt(IndexStmt *stmt, const char *queryString);
extern void analyzeRuleStmt(RuleStmt *stmt, const char *queryString,
List **actions, Node **whereClause);
extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
extern Query *transformStmt(ParseState *pstate, Node *parseTree);
extern void CheckSelectLocking(Query *qry);
extern void applyLockingClause(Query *qry, Index rtindex,
bool forUpdate, bool noWait);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.51 2007/01/05 22:19:57 momjian Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.52 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -83,6 +83,7 @@ typedef struct ParseState
} ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState);
extern void free_parsestate(ParseState *pstate);
extern int parser_errposition(ParseState *pstate, int location);
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);

View File

@ -0,0 +1,28 @@
/*-------------------------------------------------------------------------
*
* parse_utilcmd.h
* parse analysis for utility commands
*
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_utilcmd.h,v 1.1 2007/06/23 22:12:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_UTILCMD_H
#define PARSE_UTILCMD_H
#include "parser/parse_node.h"
extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString);
extern List *transformAlterTableStmt(AlterTableStmt *stmt,
const char *queryString);
extern IndexStmt *transformIndexStmt(IndexStmt *stmt, const char *queryString);
extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
List **actions, Node **whereClause);
extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
#endif /* PARSE_UTILCMD_H */