Commit bde689f8 authored by Tom Lane's avatar Tom Lane

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.
parent f7867154
...@@ -1937,7 +1937,7 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context) ...@@ -1937,7 +1937,7 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Query *query = (Query *) node; Query *query = (Query *) node;
ListCell *lc; ListCell *lc;
while (query->commandType == CMD_UTILITY) if (query->commandType == CMD_UTILITY)
{ {
/* /*
* Ignore utility statements, except those (such as EXPLAIN) that * Ignore utility statements, except those (such as EXPLAIN) that
......
...@@ -1351,25 +1351,39 @@ QueryReturnsTuples(Query *parsetree) ...@@ -1351,25 +1351,39 @@ QueryReturnsTuples(Query *parsetree)
* UtilityContainsQuery * UtilityContainsQuery
* Return the contained Query, or NULL if there is none * 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. * This function encapsulates knowledge of exactly which ones do.
* We assume it is invoked only on already-parse-analyzed statements * We assume it is invoked only on already-parse-analyzed statements
* (else the contained parsetree isn't a Query yet). * (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 * Query *
UtilityContainsQuery(Node *parsetree) UtilityContainsQuery(Node *parsetree)
{ {
Query *qry;
switch (nodeTag(parsetree)) switch (nodeTag(parsetree))
{ {
case T_ExplainStmt: case T_ExplainStmt:
Assert(IsA(((ExplainStmt *) parsetree)->query, Query)); qry = (Query *) ((ExplainStmt *) parsetree)->query;
return (Query *) ((ExplainStmt *) parsetree)->query; Assert(IsA(qry, Query));
if (qry->commandType == CMD_UTILITY)
return UtilityContainsQuery(qry->utilityStmt);
return qry;
case T_CreateTableAsStmt: case T_CreateTableAsStmt:
/* might or might not contain a Query ... */ /* might or might not contain a Query ... */
if (IsA(((CreateTableAsStmt *) parsetree)->query, Query)) qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
return (Query *) ((CreateTableAsStmt *) parsetree)->query; if (IsA(qry, Query))
Assert(IsA(((CreateTableAsStmt *) parsetree)->query, ExecuteStmt)); {
/* Recursion currently can't be necessary here */
Assert(qry->commandType != CMD_UTILITY);
return qry;
}
Assert(IsA(qry, ExecuteStmt));
return NULL; return NULL;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment