1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-26 01:22:12 +03:00

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.
This commit is contained in:
Tom Lane
2007-02-20 17:32:18 +00:00
parent 71b0cf2f6b
commit 9cbd0c155d
39 changed files with 1172 additions and 897 deletions

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.272 2007/02/14 01:58:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.273 2007/02/20 17:32:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -248,36 +248,41 @@ CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
/*
* QueryIsReadOnly: is an analyzed/rewritten query read-only?
* CommandIsReadOnly: is an executable query read-only?
*
* This is a much stricter test than we apply for XactReadOnly mode;
* the query must be *in truth* read-only, because the caller wishes
* not to do CommandCounterIncrement for it.
*
* Note: currently no need to support Query nodes here
*/
bool
QueryIsReadOnly(Query *parsetree)
CommandIsReadOnly(Node *parsetree)
{
switch (parsetree->commandType)
if (IsA(parsetree, PlannedStmt))
{
case CMD_SELECT:
if (parsetree->into != NULL)
return false; /* SELECT INTO */
else if (parsetree->rowMarks != NIL)
return false; /* SELECT FOR UPDATE/SHARE */
else
return true;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
return false;
case CMD_UTILITY:
/* For now, treat all utility commands as read/write */
return false;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) parsetree->commandType);
break;
PlannedStmt *stmt = (PlannedStmt *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
return false; /* SELECT INTO */
else if (stmt->rowMarks != NIL)
return false; /* SELECT FOR UPDATE/SHARE */
else
return true;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
return false;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
break;
}
}
/* For now, treat all utility commands as read/write */
return false;
}
@ -1161,7 +1166,7 @@ UtilityReturnsTuples(Node *parsetree)
entry = FetchPreparedStatement(stmt->name, false);
if (!entry)
return false; /* not our business to raise error */
switch (ChoosePortalStrategy(entry->query_list))
switch (ChoosePortalStrategy(entry->stmt_list))
{
case PORTAL_ONE_SELECT:
case PORTAL_ONE_RETURNING:
@ -1244,6 +1249,7 @@ UtilityTupleDescriptor(Node *parsetree)
* QueryReturnsTuples
* Return "true" if this Query will send output to the destination.
*/
#ifdef NOT_USED
bool
QueryReturnsTuples(Query *parsetree)
{
@ -1270,14 +1276,15 @@ QueryReturnsTuples(Query *parsetree)
}
return false; /* default */
}
#endif
/*
* CreateCommandTag
* utility to get a string representation of the
* command operation, given a raw (un-analyzed) parsetree.
* utility to get a string representation of the command operation,
* given either a raw (un-analyzed) parsetree or a planned query.
*
* This must handle all raw command types, but since the vast majority
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
*
* NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
@ -1290,6 +1297,7 @@ CreateCommandTag(Node *parsetree)
switch (nodeTag(parsetree))
{
/* raw plannable queries */
case T_InsertStmt:
tag = "INSERT";
break;
@ -1306,6 +1314,7 @@ CreateCommandTag(Node *parsetree)
tag = "SELECT";
break;
/* utility statements --- same whether raw or cooked */
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
@ -1826,6 +1835,95 @@ CreateCommandTag(Node *parsetree)
tag = "DEALLOCATE";
break;
/* already-planned queries */
case T_PlannedStmt:
{
PlannedStmt *stmt = (PlannedStmt *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
/*
* We take a little extra care here so that the result
* will be useful for complaints about read-only
* statements
*/
if (stmt->into != NULL)
tag = "SELECT INTO";
else if (stmt->rowMarks != NIL)
{
if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
tag = "SELECT FOR UPDATE";
else
tag = "SELECT FOR SHARE";
}
else
tag = "SELECT";
break;
case CMD_UPDATE:
tag = "UPDATE";
break;
case CMD_INSERT:
tag = "INSERT";
break;
case CMD_DELETE:
tag = "DELETE";
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
tag = "???";
break;
}
}
break;
/* parsed-and-rewritten-but-not-planned queries */
case T_Query:
{
Query *stmt = (Query *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
/*
* We take a little extra care here so that the result
* will be useful for complaints about read-only
* statements
*/
if (stmt->into != NULL)
tag = "SELECT INTO";
else if (stmt->rowMarks != NIL)
{
if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
tag = "SELECT FOR UPDATE";
else
tag = "SELECT FOR SHARE";
}
else
tag = "SELECT";
break;
case CMD_UPDATE:
tag = "UPDATE";
break;
case CMD_INSERT:
tag = "INSERT";
break;
case CMD_DELETE:
tag = "DELETE";
break;
case CMD_UTILITY:
tag = CreateCommandTag(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
tag = "???";
break;
}
}
break;
default:
elog(WARNING, "unrecognized node type: %d",
(int) nodeTag(parsetree));
@ -1836,69 +1934,13 @@ CreateCommandTag(Node *parsetree)
return tag;
}
/*
* CreateQueryTag
* utility to get a string representation of a Query operation.
*
* This is exactly like CreateCommandTag, except it works on a Query
* that has already been through parse analysis (and possibly further).
*/
const char *
CreateQueryTag(Query *parsetree)
{
const char *tag;
Assert(IsA(parsetree, Query));
switch (parsetree->commandType)
{
case CMD_SELECT:
/*
* We take a little extra care here so that the result will be
* useful for complaints about read-only statements
*/
if (parsetree->into != NULL)
tag = "SELECT INTO";
else if (parsetree->rowMarks != NIL)
{
if (((RowMarkClause *) linitial(parsetree->rowMarks))->forUpdate)
tag = "SELECT FOR UPDATE";
else
tag = "SELECT FOR SHARE";
}
else
tag = "SELECT";
break;
case CMD_UPDATE:
tag = "UPDATE";
break;
case CMD_INSERT:
tag = "INSERT";
break;
case CMD_DELETE:
tag = "DELETE";
break;
case CMD_UTILITY:
tag = CreateCommandTag(parsetree->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) parsetree->commandType);
tag = "???";
break;
}
return tag;
}
/*
* GetCommandLogLevel
* utility to get the minimum log_statement level for a command,
* given a raw (un-analyzed) parsetree.
* given either a raw (un-analyzed) parsetree or a planned query.
*
* This must handle all raw command types, but since the vast majority
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
*/
LogStmtLevel
@ -1908,6 +1950,7 @@ GetCommandLogLevel(Node *parsetree)
switch (nodeTag(parsetree))
{
/* raw plannable queries */
case T_InsertStmt:
case T_DeleteStmt:
case T_UpdateStmt:
@ -1921,6 +1964,7 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_ALL;
break;
/* utility statements --- same whether raw or cooked */
case T_TransactionStmt:
lev = LOGSTMT_ALL;
break;
@ -2216,12 +2260,12 @@ GetCommandLogLevel(Node *parsetree)
pstmt = FetchPreparedStatement(stmt->name, false);
if (pstmt)
{
foreach(l, pstmt->query_list)
foreach(l, pstmt->stmt_list)
{
Query *query = (Query *) lfirst(l);
Node *substmt = (Node *) lfirst(l);
LogStmtLevel stmt_lev;
stmt_lev = GetQueryLogLevel(query);
stmt_lev = GetCommandLogLevel(substmt);
lev = Min(lev, stmt_lev);
}
}
@ -2232,14 +2276,67 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_ALL;
break;
case T_Query:
/* already-planned queries */
case T_PlannedStmt:
{
PlannedStmt *stmt = (PlannedStmt *) parsetree;
/*
* In complicated situations (eg, EXPLAIN ANALYZE in an extended
* Query protocol), we might find an already-analyzed query within
* a utility statement. Cope.
*/
lev = GetQueryLogLevel((Query *) parsetree);
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
lev = LOGSTMT_MOD;
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
lev = LOGSTMT_ALL;
break;
}
}
break;
/* parsed-and-rewritten-but-not-planned queries */
case T_Query:
{
Query *stmt = (Query *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
lev = LOGSTMT_MOD;
break;
case CMD_UTILITY:
lev = GetCommandLogLevel(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
lev = LOGSTMT_ALL;
break;
}
}
break;
default:
@ -2251,46 +2348,3 @@ GetCommandLogLevel(Node *parsetree)
return lev;
}
/*
* GetQueryLogLevel
* utility to get the minimum log_statement level for a Query operation.
*
* This is exactly like GetCommandLogLevel, except it works on a Query
* that has already been through parse analysis (and possibly further).
*/
LogStmtLevel
GetQueryLogLevel(Query *parsetree)
{
LogStmtLevel lev;
Assert(IsA(parsetree, Query));
switch (parsetree->commandType)
{
case CMD_SELECT:
if (parsetree->into != NULL)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
lev = LOGSTMT_MOD;
break;
case CMD_UTILITY:
lev = GetCommandLogLevel(parsetree->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) parsetree->commandType);
lev = LOGSTMT_ALL;
break;
}
return lev;
}