Обсуждение: BUG #18778: Query planning fails in ExecInitExprRec with unrecognized node type

Поиск
Список
Период
Сортировка

BUG #18778: Query planning fails in ExecInitExprRec with unrecognized node type

От
PG Bug reporting form
Дата:
The following bug has been logged on the website:

Bug reference:      18778
Logged by:          Alexander Lakhin
Email address:      exclusion@gmail.com
PostgreSQL version: 17.2
Operating system:   Ubuntu 24.04
Description:

The following script:
CREATE TABLE t (id int, PRIMARY KEY (id)) PARTITION BY RANGE (id);
CREATE TABLE t0 PARTITION OF t FOR VALUES FROM (0) TO (1);
CREATE TABLE t1 PARTITION OF t FOR VALUES FROM (1) TO (2);

SELECT 1 FROM (SELECT EXISTS (SELECT 1 FROM t0 WHERE id = t00.id) AS b FROM
t0 t00) r, t
WHERE t.id > CASE WHEN jsonb_build_object(b) IS NULL THEN 1 ELSE 1 END;

fails with:
ERROR:  XX000: unrecognized node type: 24
LOCATION:  ExecInitExprRec, execExpr.c:2657

The first bad commit for this anomaly (discovered with SQLsmith) is
41efb8340.


PG Bug reporting form <noreply@postgresql.org> writes:
> The following script:
> CREATE TABLE t (id int, PRIMARY KEY (id)) PARTITION BY RANGE (id);
> CREATE TABLE t0 PARTITION OF t FOR VALUES FROM (0) TO (1);
> CREATE TABLE t1 PARTITION OF t FOR VALUES FROM (1) TO (2);

> SELECT 1 FROM (SELECT EXISTS (SELECT 1 FROM t0 WHERE id = t00.id) AS b FROM
> t0 t00) r, t
> WHERE t.id > CASE WHEN jsonb_build_object(b) IS NULL THEN 1 ELSE 1 END;

> fails with:
> ERROR:  XX000: unrecognized node type: 24

Thanks for the report!  setrefs.c is supposed to remove
AlternativeSubPlan nodes from the plan, but it's failing to do so
here.  Digging, the un-cleaned-up AlternativeSubPlan is inside the
exec_pruning_steps of an Append node's part_prune_info, and I see
that setrefs is totally unaware that those expressions might need
processing.  I think it ought to be applying fix_scan_expr to them,
as per the attached.  There are a bunch of tidying-up things that
fix_scan_expr does, so I suspect that there may be more bug symptoms
reachable from this oversight.  Some of the missed processing may be
redundant --- for example it's likely that
record_plan_function_dependency is duplicative because functions used
here would also be used elsewhere in the query.  But it's hard to
believe it all is.

            regards, tom lane

diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index fff2655595..1e7b7bc6ff 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1795,6 +1795,12 @@ set_append_references(PlannerInfo *root,
                 PartitionedRelPruneInfo *pinfo = lfirst(l2);

                 pinfo->rtindex += rtoffset;
+                pinfo->initial_pruning_steps =
+                    fix_scan_list(root, pinfo->initial_pruning_steps,
+                                  rtoffset, 1);
+                pinfo->exec_pruning_steps =
+                    fix_scan_list(root, pinfo->exec_pruning_steps,
+                                  rtoffset, 1);
             }
         }
     }
@@ -1871,6 +1877,12 @@ set_mergeappend_references(PlannerInfo *root,
                 PartitionedRelPruneInfo *pinfo = lfirst(l2);

                 pinfo->rtindex += rtoffset;
+                pinfo->initial_pruning_steps =
+                    fix_scan_list(root, pinfo->initial_pruning_steps,
+                                  rtoffset, 1);
+                pinfo->exec_pruning_steps =
+                    fix_scan_list(root, pinfo->exec_pruning_steps,
+                                  rtoffset, 1);
             }
         }
     }

Re: BUG #18778: Query planning fails in ExecInitExprRec with unrecognized node type

От
Zhang Mingli
Дата:


Zhang Mingli
www.hashdata.xyz
On Jan 17, 2025 at 07:35 +0800, Tom Lane <tgl@sss.pgh.pa.us>, wrote:
PG Bug reporting form <noreply@postgresql.org> writes:
The following script:
CREATE TABLE t (id int, PRIMARY KEY (id)) PARTITION BY RANGE (id);
CREATE TABLE t0 PARTITION OF t FOR VALUES FROM (0) TO (1);
CREATE TABLE t1 PARTITION OF t FOR VALUES FROM (1) TO (2);

SELECT 1 FROM (SELECT EXISTS (SELECT 1 FROM t0 WHERE id = t00.id) AS b FROM
t0 t00) r, t
WHERE t.id > CASE WHEN jsonb_build_object(b) IS NULL THEN 1 ELSE 1 END;

fails with:
ERROR: XX000: unrecognized node type: 24

Thanks for the report! setrefs.c is supposed to remove
AlternativeSubPlan nodes from the plan, but it's failing to do so
here. Digging, the un-cleaned-up AlternativeSubPlan is inside the
exec_pruning_steps of an Append node's part_prune_info, and I see
that setrefs is totally unaware that those expressions might need
processing. I think it ought to be applying fix_scan_expr to them,
as per the attached. There are a bunch of tidying-up things that
fix_scan_expr does, so I suspect that there may be more bug symptoms
reachable from this oversight. Some of the missed processing may be
redundant --- for example it's likely that
record_plan_function_dependency is duplicative because functions used
here would also be used elsewhere in the query. But it's hard to
believe it all is.

Hi, I have tested the patch, and confirm that it works well. Additionally, I believe it might be worth creating a test case for it.

And I have a question that may not be directly related to the issue: why is there a Subplan 2, and it appears to be unused?

explain(costs off, verbose) SELECT 1 FROM (SELECT EXISTS (SELECT 1 FROM t0 WHERE id = t00.id) AS b FROM
t0 t00) r, t WHERE t.id > CASE WHEN jsonb_build_object(b) IS NULL THEN 1 ELSE 1 END;
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Output: 1
   ->  Seq Scan on public.t0 t00
         Output: t00.id
   ->  Append
         ->  Index Only Scan using t0_pkey on public.t0 t_1
               Output: t_1.id
               Index Cond: (t_1.id > CASE WHEN (jsonb_build_object(EXISTS(SubPlan 1)) IS NULL) THEN 1 ELSE 1 END)
               SubPlan 2
                 ->  Seq Scan on public.t0 t0_1
                       Output: t0_1.id
         ->  Index Only Scan using t1_pkey on public.t1 t_2
               Output: t_2.id
               Index Cond: (t_2.id > CASE WHEN (jsonb_build_object(EXISTS(SubPlan 1)) IS NULL) THEN 1 ELSE 1 END)
         SubPlan 1
           ->  Index Only Scan using t0_pkey on public.t0
                 Index Cond: (t0.id = t00.id)
(17 rows)

 

Zhang Mingli <zmlpostgres@gmail.com> writes:
> And I have a question that may not be directly related to the issue: why is there a Subplan 2, and it appears to be
unused?

Yeah, that's because the AlternativeSubPlan originally had two child
subplans: a parameterized one intended for a few calls, and a hashed
one to be used for a lot of calls.  We build both because at the time
when this needs to happen, we don't have any clue how many calls
there will be.  We wait till the very end of planning to decide which
one is more likely to win based on context, and then discard the
AlternativeSubPlan, replacing it with a direct reference to the chosen
SubPlan.  But the other one stays in the tree.  Getting rid of it
seemed complicated, and it won't be referenced at runtime so there's
not much penalty from leaving it there.  It is confusing, I admit.

            regards, tom lane