mirror of
https://github.com/postgres/postgres.git
synced 2025-12-01 12:18:01 +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/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,
|
||||
¶mTypes,
|
||||
&numParams);
|
||||
query = parse_analyze_varparams(copyObject(raw_parse_tree),
|
||||
query_string,
|
||||
¶mTypes,
|
||||
&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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user