From 8b5962063344a19258709bc2302db8e473125067 Mon Sep 17 00:00:00 2001 From: naisila Date: Sun, 10 Nov 2024 23:13:19 +0300 Subject: [PATCH] Ruleutils_17 Fix "failed to find plan for subquery/CTE" errors in EXPLAIN. Relevant PG commit: https://github.com/postgres/postgres/commit/81a12a4477533d7722bd6b6dac88b0e798f8e85b 81a12a4477533d7722bd6b6dac88b0e798f8e85b --- .../distributed/deparser/ruleutils_17.c | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/backend/distributed/deparser/ruleutils_17.c b/src/backend/distributed/deparser/ruleutils_17.c index fa2a854b0..f89e69696 100644 --- a/src/backend/distributed/deparser/ruleutils_17.c +++ b/src/backend/distributed/deparser/ruleutils_17.c @@ -4633,17 +4633,30 @@ get_name_for_var_field(Var *var, int fieldno, /* * We're deparsing a Plan tree so we don't have complete * RTE entries (in particular, rte->subquery is NULL). But - * the only place we'd see a Var directly referencing a - * SUBQUERY RTE is in a SubqueryScan plan node, and we can - * look into the child plan's tlist instead. + * the only place we'd normally see a Var directly + * referencing a SUBQUERY RTE is in a SubqueryScan plan + * node, and we can look into the child plan's tlist + * instead. An exception occurs if the subquery was + * proven empty and optimized away: then we'd find such a + * Var in a childless Result node, and there's nothing in + * the plan tree that would let us figure out what it had + * originally referenced. In that case, fall back on + * printing "fN", analogously to the default column names + * for RowExprs. */ TargetEntry *tle; deparse_namespace save_dpns; const char *result; if (!dpns->inner_plan) - elog(ERROR, "failed to find plan for subquery %s", - rte->eref->aliasname); + { + char *dummy_name = palloc(32); + Assert(IsA(dpns->plan, Result)); + snprintf(dummy_name, 32, "f%d", fieldno); + return dummy_name; + } + Assert(IsA(dpns->plan, SubqueryScan)); + tle = get_tle_by_resno(dpns->inner_tlist, attnum); if (!tle) elog(ERROR, "bogus varattno for subquery var: %d", @@ -4752,20 +4765,29 @@ get_name_for_var_field(Var *var, int fieldno, { /* * We're deparsing a Plan tree so we don't have a CTE - * list. But the only places we'd see a Var directly - * referencing a CTE RTE are in CteScan or WorkTableScan - * plan nodes. For those cases, set_deparse_plan arranged - * for dpns->inner_plan to be the plan node that emits the - * CTE or RecursiveUnion result, and we can look at its - * tlist instead. + * list. But the only places we'd normally see a Var + * directly referencing a CTE RTE are in CteScan or + * WorkTableScan plan nodes. For those cases, + * set_deparse_plan arranged for dpns->inner_plan to be + * the plan node that emits the CTE or RecursiveUnion + * result, and we can look at its tlist instead. As + * above, this can fail if the CTE has been proven empty, + * in which case fall back to "fN". */ TargetEntry *tle; deparse_namespace save_dpns; const char *result; if (!dpns->inner_plan) - elog(ERROR, "failed to find plan for CTE %s", - rte->eref->aliasname); + { + char *dummy_name = palloc(32); + Assert(IsA(dpns->plan, Result)); + snprintf(dummy_name, 32, "f%d", fieldno); + return dummy_name; + } + Assert(IsA(dpns->plan, CteScan) || + IsA(dpns->plan, WorkTableScan)); + tle = get_tle_by_resno(dpns->inner_tlist, attnum); if (!tle) elog(ERROR, "bogus varattno for subquery var: %d",