aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-02-20 17:32:18 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-02-20 17:32:18 +0000
commit9cbd0c155d1602aad879f510256b626c58942080 (patch)
tree6d5504a4e841313d3a29cead80067006dc408e39 /src/backend/tcop/postgres.c
parent71b0cf2f6bec3129f2c3f574d4e47408c2dc2516 (diff)
downloadpostgresql-9cbd0c155d1602aad879f510256b626c58942080.tar.gz
postgresql-9cbd0c155d1602aad879f510256b626c58942080.zip
Remove the Query structure from the executor's API. This allows us to stop
storing mostly-redundant Query trees in prepared statements, portals, etc. To replace Query, a new node type called PlannedStmt is inserted by the planner at the top of a completed plan tree; this carries just the fields of Query that are still needed at runtime. The statement lists kept in portals etc. now consist of intermixed PlannedStmt and bare utility-statement nodes --- no Query. This incidentally allows us to remove some fields from Query and Plan nodes that shouldn't have been there in the first place. Still to do: simplify the execution-time range table; at the moment the range table passed to the executor still contains Query trees for subqueries. initdb forced due to change of stored rules.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c150
1 files changed, 74 insertions, 76 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f00897ee622..1c40a8752e9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.524 2007/02/17 19:33:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.525 2007/02/20 17:32:16 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -165,8 +165,7 @@ static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static List *pg_rewrite_queries(List *querytree_list);
-static bool check_log_statement_raw(List *raw_parsetree_list);
-static bool check_log_statement_cooked(List *parsetree_list);
+static bool check_log_statement(List *stmt_list);
static int errdetail_execute(List *raw_parsetree_list);
static int errdetail_params(ParamListInfo params);
static void start_xact_command(void);
@@ -659,10 +658,10 @@ pg_rewrite_queries(List *querytree_list)
/* Generate a plan for a single already-rewritten query. */
-Plan *
+PlannedStmt *
pg_plan_query(Query *querytree, ParamListInfo boundParams)
{
- Plan *plan;
+ PlannedStmt *plan;
/* Utility commands have no plans. */
if (querytree->commandType == CMD_UTILITY)
@@ -680,7 +679,7 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams)
#ifdef COPY_PARSE_PLAN_TREES
/* Optional debugging check: pass plan output through copyObject() */
{
- Plan *new_plan = (Plan *) copyObject(plan);
+ PlannedStmt *new_plan = (PlannedStmt *) copyObject(plan);
/*
* equal() currently does not have routines to compare Plan nodes, so
@@ -715,23 +714,26 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams)
* utility statements depend on not having frozen the snapshot yet.
* (We assume that such statements cannot appear together with plannable
* statements in the rewriter's output.)
+ *
+ * Normal optimizable statements generate PlannedStmt entries in the result
+ * list. Utility statements are simply represented by their statement nodes.
*/
List *
pg_plan_queries(List *querytrees, ParamListInfo boundParams,
bool needSnapshot)
{
- List *plan_list = NIL;
+ List *stmt_list = NIL;
ListCell *query_list;
foreach(query_list, querytrees)
{
Query *query = (Query *) lfirst(query_list);
- Plan *plan;
+ Node *stmt;
if (query->commandType == CMD_UTILITY)
{
/* Utility commands have no plans. */
- plan = NULL;
+ stmt = query->utilityStmt;
}
else
{
@@ -740,13 +742,13 @@ pg_plan_queries(List *querytrees, ParamListInfo boundParams,
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
needSnapshot = false;
}
- plan = pg_plan_query(query, boundParams);
+ stmt = (Node *) pg_plan_query(query, boundParams);
}
- plan_list = lappend(plan_list, plan);
+ stmt_list = lappend(stmt_list, stmt);
}
- return plan_list;
+ return stmt_list;
}
@@ -817,7 +819,7 @@ exec_simple_query(const char *query_string)
parsetree_list = pg_parse_query(query_string);
/* Log immediately if dictated by log_statement */
- if (check_log_statement_raw(parsetree_list))
+ if (check_log_statement(parsetree_list))
{
ereport(LOG,
(errmsg("statement: %s", query_string),
@@ -905,7 +907,6 @@ exec_simple_query(const char *query_string)
NULL,
query_string,
commandTag,
- querytree_list,
plantree_list,
MessageContext);
@@ -1050,9 +1051,10 @@ exec_parse_message(const char *query_string, /* string to execute */
List *parsetree_list;
const char *commandTag;
List *querytree_list,
- *plantree_list,
+ *stmt_list,
*param_list;
bool is_named;
+ bool fully_planned;
bool save_log_statement_stats = log_statement_stats;
char msec_str[32];
@@ -1202,17 +1204,23 @@ exec_parse_message(const char *query_string, /* string to execute */
* planning until Bind. Otherwise do it now.
*/
if (!is_named && numParams > 0)
- plantree_list = NIL;
+ {
+ stmt_list = querytree_list;
+ fully_planned = false;
+ }
else
- plantree_list = pg_plan_queries(querytree_list, NULL, true);
+ {
+ stmt_list = pg_plan_queries(querytree_list, NULL, true);
+ fully_planned = true;
+ }
}
else
{
/* Empty input string. This is legal. */
commandTag = NULL;
- querytree_list = NIL;
- plantree_list = NIL;
+ stmt_list = NIL;
param_list = NIL;
+ fully_planned = true;
}
/* If we got a cancel signal in analysis or planning, quit */
@@ -1226,9 +1234,9 @@ exec_parse_message(const char *query_string, /* string to execute */
StorePreparedStatement(stmt_name,
query_string,
commandTag,
- querytree_list,
- plantree_list,
+ stmt_list,
param_list,
+ fully_planned,
false);
}
else
@@ -1240,9 +1248,9 @@ exec_parse_message(const char *query_string, /* string to execute */
pstmt->query_string = pstrdup(query_string);
/* the rest is there already */
pstmt->commandTag = commandTag;
- pstmt->query_list = querytree_list;
- pstmt->plan_list = plantree_list;
+ pstmt->stmt_list = stmt_list;
pstmt->argtype_list = param_list;
+ pstmt->fully_planned = fully_planned;
pstmt->from_sql = false;
pstmt->context = unnamed_stmt_context;
/* Now the unnamed statement is complete and valid */
@@ -1393,7 +1401,7 @@ exec_bind_message(StringInfo input_message)
* functions.
*/
if (IsAbortedTransactionBlockState() &&
- (!IsTransactionExitStmtList(pstmt->query_list) ||
+ (!IsTransactionExitStmtList(pstmt->stmt_list) ||
numParams != 0))
ereport(ERROR,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
@@ -1581,22 +1589,21 @@ exec_bind_message(StringInfo input_message)
* portal's queryContext becomes its own heap context rather than the
* prepared statement's context. FIXME someday
*/
- if (pstmt->plan_list == NIL && pstmt->query_list != NIL)
+ if (pstmt->fully_planned)
+ {
+ plan_list = pstmt->stmt_list;
+ qContext = pstmt->context;
+ }
+ else
{
MemoryContext oldContext;
qContext = PortalGetHeapMemory(portal);
oldContext = MemoryContextSwitchTo(qContext);
- query_list = copyObject(pstmt->query_list);
+ query_list = copyObject(pstmt->stmt_list);
plan_list = pg_plan_queries(query_list, params, true);
MemoryContextSwitchTo(oldContext);
}
- else
- {
- query_list = pstmt->query_list;
- plan_list = pstmt->plan_list;
- qContext = pstmt->context;
- }
/*
* Define portal and start execution.
@@ -1605,7 +1612,6 @@ exec_bind_message(StringInfo input_message)
*pstmt->stmt_name ? pstmt->stmt_name : NULL,
pstmt->query_string,
pstmt->commandTag,
- query_list,
plan_list,
qContext);
@@ -1688,13 +1694,13 @@ exec_execute_message(const char *portal_name, long max_rows)
*/
if (portal->commandTag == NULL)
{
- Assert(portal->parseTrees == NIL);
+ Assert(portal->stmts == NIL);
NullCommand(dest);
return;
}
/* Does the portal contain a transaction command? */
- is_xact_command = IsTransactionStmtList(portal->parseTrees);
+ is_xact_command = IsTransactionStmtList(portal->stmts);
/*
* We must copy the sourceText and prepStmtName into MessageContext in
@@ -1760,7 +1766,7 @@ exec_execute_message(const char *portal_name, long max_rows)
execute_is_fetch = !portal->atStart;
/* Log immediately if dictated by log_statement */
- if (check_log_statement_cooked(portal->parseTrees))
+ if (check_log_statement(portal->stmts))
{
ereport(LOG,
(errmsg("%s %s%s%s%s%s",
@@ -1781,7 +1787,7 @@ exec_execute_message(const char *portal_name, long max_rows)
* actually run are those containing COMMIT or ROLLBACK commands.
*/
if (IsAbortedTransactionBlockState() &&
- !IsTransactionExitStmtList(portal->parseTrees))
+ !IsTransactionExitStmtList(portal->stmts))
ereport(ERROR,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("current transaction is aborted, "
@@ -1865,15 +1871,16 @@ exec_execute_message(const char *portal_name, long max_rows)
}
/*
- * check_log_statement_raw
+ * check_log_statement
* Determine whether command should be logged because of log_statement
*
- * raw_parsetree_list is the raw grammar output
+ * parsetree_list can be either raw grammar output or a list of planned
+ * statements
*/
static bool
-check_log_statement_raw(List *raw_parsetree_list)
+check_log_statement(List *stmt_list)
{
- ListCell *parsetree_item;
+ ListCell *stmt_item;
if (log_statement == LOGSTMT_NONE)
return false;
@@ -1881,37 +1888,11 @@ check_log_statement_raw(List *raw_parsetree_list)
return true;
/* Else we have to inspect the statement(s) to see whether to log */
- foreach(parsetree_item, raw_parsetree_list)
+ foreach(stmt_item, stmt_list)
{
- Node *parsetree = (Node *) lfirst(parsetree_item);
+ Node *stmt = (Node *) lfirst(stmt_item);
- if (GetCommandLogLevel(parsetree) <= log_statement)
- return true;
- }
-
- return false;
-}
-
-/*
- * check_log_statement_cooked
- * As above, but work from already-analyzed querytrees
- */
-static bool
-check_log_statement_cooked(List *parsetree_list)
-{
- ListCell *parsetree_item;
-
- if (log_statement == LOGSTMT_NONE)
- return false;
- if (log_statement == LOGSTMT_ALL)
- return true;
-
- /* Else we have to inspect the statement(s) to see whether to log */
- foreach(parsetree_item, parsetree_list)
- {
- Query *parsetree = (Query *) lfirst(parsetree_item);
-
- if (GetQueryLogLevel(parsetree) <= log_statement)
+ if (GetCommandLogLevel(stmt) <= log_statement)
return true;
}
@@ -2259,6 +2240,7 @@ finish_xact_command(void)
* ones that we allow in transaction-aborted state.
*/
+/* Test a bare parsetree */
static bool
IsTransactionExitStmt(Node *parsetree)
{
@@ -2275,29 +2257,45 @@ IsTransactionExitStmt(Node *parsetree)
return false;
}
+/* Test a list that might contain Query nodes or bare parsetrees */
static bool
IsTransactionExitStmtList(List *parseTrees)
{
if (list_length(parseTrees) == 1)
{
- Query *query = (Query *) linitial(parseTrees);
+ Node *stmt = (Node *) linitial(parseTrees);
+
+ if (IsA(stmt, Query))
+ {
+ Query *query = (Query *) stmt;
- if (query->commandType == CMD_UTILITY &&
- IsTransactionExitStmt(query->utilityStmt))
+ if (query->commandType == CMD_UTILITY &&
+ IsTransactionExitStmt(query->utilityStmt))
+ return true;
+ }
+ else if (IsTransactionExitStmt(stmt))
return true;
}
return false;
}
+/* Test a list that might contain Query nodes or bare parsetrees */
static bool
IsTransactionStmtList(List *parseTrees)
{
if (list_length(parseTrees) == 1)
{
- Query *query = (Query *) linitial(parseTrees);
+ Node *stmt = (Node *) linitial(parseTrees);
- if (query->commandType == CMD_UTILITY &&
- query->utilityStmt && IsA(query->utilityStmt, TransactionStmt))
+ if (IsA(stmt, Query))
+ {
+ Query *query = (Query *) stmt;
+
+ if (query->commandType == CMD_UTILITY &&
+ IsA(query->utilityStmt, TransactionStmt))
+ return true;
+ }
+ else if (IsA(stmt, TransactionStmt))
return true;
}
return false;