On Thu, Aug 8, 2024 at 8:23 AM PG Bug reporting form
<noreply@postgresql.org> wrote:
> From a clean DB, one can execute:
> EXPLAIN (VERBOSE) SELECT FROM information_schema.element_types WHERE
> object_type = 'TABLE';
> Which returns:
> ERROR: failed to find plan for subquery ss
Thanks for the report!
I think the problem is that when we see a Var that references a
SUBQUERY RTE when deparsing a Plan tree to get the name of a field, we
assume that we are in a SubqueryScan plan node, in which case the code
is no problem because set_deparse_plan has set dpns->inner_plan to its
child plan. However, this bug shows that this assumption does not
always hold: we might instead be in a Result node with a Var
referencing a SUBQUERY RTE. This problem can be reproduced with the
query below.
EXPLAIN (VERBOSE, COSTS OFF)
SELECT (ss.a).x, (ss.a).n FROM
(SELECT information_schema._pg_expandarray(ARRAY[1,2]) AS a) ss
WHERE FALSE;
ERROR: failed to find plan for subquery ss
In this case, due to the constant false filter, the whole plan is
reduced to a dummy Result node, with a targetlist consisting of 'a.x'
and 'a.n', where 'a' is a Var referencing the SUBQUERY RTE. We do not
generate a SubqueryScan plan node for the subquery, as the relation is
recognized as dummy. That is to say, we neither have a valid
rte->subquery nor a valid SubqueryScan plan node. So it seems to me
that there is no easy way to get the names of the fields in this case.
I'm wondering whether we can just compose a fake name with something
like below?
@@ -7903,6 +7903,14 @@ get_name_for_var_field(Var *var, int fieldno,
deparse_namespace save_dpns;
const char *result;
+ if (IsA(dpns->plan, Result))
+ {
+ char *fakeCol = palloc(32);
+
+ snprintf(fakeCol, sizeof(fakeCol), "col%d", fieldno);
+ return fakeCol;
+ }
+
if (!dpns->inner_plan)
elog(ERROR, "failed to find plan for subquery %s",
rte->eref->aliasname);
This same problem can also happen to CTEs.
EXPLAIN (VERBOSE, COSTS OFF)
WITH ss AS MATERIALIZED
(SELECT information_schema._pg_expandarray(ARRAY[1,2]) AS a)
SELECT (ss.a).x, (ss.a).n FROM ss WHERE FALSE;
ERROR: failed to find plan for CTE ss
Thanks
Richard