aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-06-27 23:18:30 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-06-27 23:18:30 -0400
commitbde689f809027422d4c0baaa3e63b69ce5762e2c (patch)
tree1e183710a3c5fb6f64b965b2cd010e01fc50ec68 /src
parentf7867154129781ee1522344bef50890c01f2b47a (diff)
downloadpostgresql-bde689f809027422d4c0baaa3e63b69ce5762e2c.tar.gz
postgresql-bde689f809027422d4c0baaa3e63b69ce5762e2c.zip
Make UtilityContainsQuery recurse until it finds a non-utility Query.
The callers of UtilityContainsQuery want it to return a non-utility Query if it returns anything at all. However, since we made CREATE TABLE AS/SELECT INTO into a utility command instead of a variant of SELECT, a command like "EXPLAIN SELECT INTO" results in two nested utility statements. So what we need UtilityContainsQuery to do is drill down to the bottom non-utility Query. I had thought of this possibility in setrefs.c, and fixed it there by looping around the UtilityContainsQuery call; but overlooked that the call sites in plancache.c have a similar issue. In those cases it's notationally inconvenient to provide an external loop, so let's redefine UtilityContainsQuery as recursing down to a non-utility Query instead. Noted by Rushabh Lathia. This is a somewhat cleaned-up version of his proposed patch.
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/plan/setrefs.c2
-rw-r--r--src/backend/tcop/utility.c26
2 files changed, 21 insertions, 7 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index f375b5f76d4..ccd69fc3660 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1937,7 +1937,7 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Query *query = (Query *) node;
ListCell *lc;
- while (query->commandType == CMD_UTILITY)
+ if (query->commandType == CMD_UTILITY)
{
/*
* Ignore utility statements, except those (such as EXPLAIN) that
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 8b73858300e..33b292e6b7a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1351,25 +1351,39 @@ QueryReturnsTuples(Query *parsetree)
* UtilityContainsQuery
* Return the contained Query, or NULL if there is none
*
- * Certain utility statements, such as EXPLAIN, contain a Query.
+ * Certain utility statements, such as EXPLAIN, contain a plannable Query.
* This function encapsulates knowledge of exactly which ones do.
* We assume it is invoked only on already-parse-analyzed statements
* (else the contained parsetree isn't a Query yet).
+ *
+ * In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO),
+ * potentially Query-containing utility statements can be nested. This
+ * function will drill down to a non-utility Query, or return NULL if none.
*/
Query *
UtilityContainsQuery(Node *parsetree)
{
+ Query *qry;
+
switch (nodeTag(parsetree))
{
case T_ExplainStmt:
- Assert(IsA(((ExplainStmt *) parsetree)->query, Query));
- return (Query *) ((ExplainStmt *) parsetree)->query;
+ qry = (Query *) ((ExplainStmt *) parsetree)->query;
+ Assert(IsA(qry, Query));
+ if (qry->commandType == CMD_UTILITY)
+ return UtilityContainsQuery(qry->utilityStmt);
+ return qry;
case T_CreateTableAsStmt:
/* might or might not contain a Query ... */
- if (IsA(((CreateTableAsStmt *) parsetree)->query, Query))
- return (Query *) ((CreateTableAsStmt *) parsetree)->query;
- Assert(IsA(((CreateTableAsStmt *) parsetree)->query, ExecuteStmt));
+ qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
+ if (IsA(qry, Query))
+ {
+ /* Recursion currently can't be necessary here */
+ Assert(qry->commandType != CMD_UTILITY);
+ return qry;
+ }
+ Assert(IsA(qry, ExecuteStmt));
return NULL;
default: