From: David Rowley Date: Fri, 31 Jul 2026 01:16:29 +0000 (+1200) Subject: Fix incorrect Result node flattening logic X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a791db9bdbd48280e752578b93909995f93fe49;p=thirdparty%2Fpostgresql.git Fix incorrect Result node flattening logic This fixes some incorrect flattening of nested Result nodes during create_plan that was introduced by f2bae51df. That commit failed to maintain the logic that checks for subplans and gating quals from the nested Result node before flattening, and that could result in the nested gating qual and subplan being lost, which could produce incorrect results. Bug: #19579 Reported-by: Viktor Leis Author: Ayush Tiwari Reviewed-by: David Rowley Discussion: https://postgr.es/m/19579-e6296b6c9fc0591c@postgresql.org Backpatch-through: 19 --- diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index de6a183da79..d8a266c386d 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1027,21 +1027,22 @@ create_gating_plan(PlannerInfo *root, Path *path, Plan *plan, (Node *) gating_quals, plan); /* - * We might have had a trivial Result plan already. Stacking one Result - * atop another is silly, so if that applies, just discard the input plan. - * (We're assuming its targetlist is uninteresting; it should be either - * the same as the result of build_path_tlist, or a simplified version. - * However, we preserve the set of relids that it purports to scan and - * attribute that to our replacement Result instead, and likewise for the - * result_type.) + * See if we can reduce down stacked Result nodes to a single node. This + * is only possible when the nested Result has no subplan and no gating + * qual. If we do remove the nested Result, we maintain the relids and + * result_type for EXPLAIN. */ if (IsA(plan, Result)) { Result *rplan = (Result *) plan; - gplan->plan.lefttree = NULL; - gplan->relids = rplan->relids; - gplan->result_type = rplan->result_type; + if (rplan->plan.lefttree == NULL && + rplan->resconstantqual == NULL) + { + gplan->plan.lefttree = NULL; + gplan->relids = rplan->relids; + gplan->result_type = rplan->result_type; + } } /* diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 19e2cca548b..05f359d3aa7 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -6707,6 +6707,17 @@ select p.* from One-Time Filter: false (3 rows) +-- Ensure multiple gating quals are evaluated correctly +select * from ( + select c0 from + (select null::int as c0 from ((select 1) union all (select 2))) t1 + full join (select 1) t2 on true + where c0 is not null +) t3 where now() is not null; + c0 +---- +(0 rows) + -- bug 5255: this is not optimizable by join removal begin; CREATE TEMP TABLE a (id int PRIMARY KEY); diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 85aed7bf704..450bd5bbf2c 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -2487,6 +2487,14 @@ select p.* from (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k where p.k = 1 and p.k = 2; +-- Ensure multiple gating quals are evaluated correctly +select * from ( + select c0 from + (select null::int as c0 from ((select 1) union all (select 2))) t1 + full join (select 1) t2 on true + where c0 is not null +) t3 where now() is not null; + -- bug 5255: this is not optimizable by join removal begin;