mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
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.
This commit is contained in:
parent
f786715412
commit
bde689f809
@ -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)
|
|||||||
* 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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user