From efeb12ef0bfef0b5aa966a56bb4dbb1f936bda0c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 20 Jun 2023 10:29:57 -0400 Subject: [PATCH] Don't include outer join relids in lateral_relids bitmapsets. This avoids an assertion failure when outer joins are rearranged per identity 3. Listing only the baserels from a PlaceHolderVar's ph_lateral set should be enough to ensure that the required values are available when we need to compute the PHV --- it's what we did before inventing nullingrel sets, after all. It's a bit unsatisfying; but with beta2 hard upon us, there's not time to look for an aesthetically cleaner fix. Richard Guo and Tom Lane Discussion: https://postgr.es/m/CAMbWs48Jcw-NvnxT23WiHP324wG44DvzcH1j4hc0Zn+3sR9cfg@mail.gmail.com --- src/backend/optimizer/plan/initsplan.c | 16 +++++++++++++--- src/test/regress/expected/join.out | 17 +++++++++++++++++ src/test/regress/sql/join.sql | 7 +++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 69ef483d283..b31d8921211 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -580,6 +580,7 @@ create_lateral_join_info(PlannerInfo *root) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); Relids eval_at = phinfo->ph_eval_at; + Relids lateral_refs; int varno; if (phinfo->ph_lateral == NULL) @@ -587,6 +588,15 @@ create_lateral_join_info(PlannerInfo *root) found_laterals = true; + /* + * Include only baserels not outer joins in the evaluation sites' + * lateral relids. This avoids problems when outer join order gets + * rearranged, and it should still ensure that the lateral values are + * available when needed. + */ + lateral_refs = bms_intersect(phinfo->ph_lateral, root->all_baserels); + Assert(!bms_is_empty(lateral_refs)); + if (bms_get_singleton_member(eval_at, &varno)) { /* Evaluation site is a baserel */ @@ -594,10 +604,10 @@ create_lateral_join_info(PlannerInfo *root) brel->direct_lateral_relids = bms_add_members(brel->direct_lateral_relids, - phinfo->ph_lateral); + lateral_refs); brel->lateral_relids = bms_add_members(brel->lateral_relids, - phinfo->ph_lateral); + lateral_refs); } else { @@ -610,7 +620,7 @@ create_lateral_join_info(PlannerInfo *root) if (brel == NULL) continue; /* ignore outer joins in eval_at */ brel->lateral_relids = bms_add_members(brel->lateral_relids, - phinfo->ph_lateral); + lateral_refs); } } } diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 35476a0d126..cd1163d039b 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2624,6 +2624,23 @@ select * from int8_tbl t1 -> Function Scan on generate_series (7 rows) +explain (costs off) +select * from int8_tbl t1 + left join int8_tbl t2 on true + left join lateral + (select t2.q1 from int8_tbl t3) s + on t2.q1 = 1; + QUERY PLAN +------------------------------------------- + Nested Loop Left Join + -> Seq Scan on int8_tbl t1 + -> Materialize + -> Nested Loop Left Join + Join Filter: (t2.q1 = 1) + -> Seq Scan on int8_tbl t2 + -> Seq Scan on int8_tbl t3 +(7 rows) + explain (costs off) select * from onek t1 left join onek t2 on true diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index d8d9579092d..7ca737eec0f 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -528,6 +528,13 @@ select * from int8_tbl t1 (select * from generate_series(t2.q1, 100)) s on t2.q1 = 1; +explain (costs off) +select * from int8_tbl t1 + left join int8_tbl t2 on true + left join lateral + (select t2.q1 from int8_tbl t3) s + on t2.q1 = 1; + explain (costs off) select * from onek t1 left join onek t2 on true