Don't include outer join relids in lateral_relids bitmapsets.
authorTom Lane <[email protected]>
Tue, 20 Jun 2023 14:29:57 +0000 (10:29 -0400)
committerTom Lane <[email protected]>
Tue, 20 Jun 2023 14:29:57 +0000 (10:29 -0400)
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
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 69ef483d283336d246372ad003bfd73a2369aff7..b31d8921211e0e93a00bd755abc869f03f66a5f0 100644 (file)
@@ -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);
            }
        }
    }
index 35476a0d1264cff65f7f4af181b2a2f80695e969..cd1163d039bd46671428793f900ef7d29dd35cbc 100644 (file)
@@ -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
index d8d9579092d53d6f74cf97af3cae43775911df8e..7ca737eec0fdad85d3eebf223db3b85454d2e67b 100644 (file)
@@ -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