Fix Asserts in calc_non_nestloop_required_outer().
authorTom Lane
Wed, 10 Jan 2024 18:51:36 +0000 (13:51 -0500)
committerTom Lane
Wed, 10 Jan 2024 18:51:36 +0000 (13:51 -0500)
These were not testing the same thing as the comparable Assert
in calc_nestloop_required_outer(), because we neglected to map
the given Paths' relids to top-level relids.  When considering
a partition child join the latter is the correct thing to do.

This oversight is old, but since it's only an overly-weak Assert
check there doesn't seem to be much value in back-patching.

Richard Guo (with cosmetic changes and comment updates by me)

Discussion: https://postgr.es/m/CAMbWs49sqbe9GBZ8sy8dSfKRNURgicR85HX8vgzcgQsPF0XY1w@mail.gmail.com

src/backend/optimizer/path/joinpath.c
src/backend/optimizer/util/pathnode.c

index 3fd5a24fadca42305ad4a7cc9458115dd6d36d73..e9def9d540ab23c421856751363a7777ca7a49a4 100644 (file)
@@ -730,8 +730,11 @@ try_nestloop_path(PlannerInfo *root,
        return;
 
    /*
-    * Paths are parameterized by top-level parents, so run parameterization
-    * tests on the parent relids.
+    * Any parameterization of the input paths refers to topmost parents of
+    * the relevant relations, because reparameterize_path_by_child() hasn't
+    * been called yet.  So we must consider topmost parents of the relations
+    * being joined, too, while determining parameterization of the result and
+    * checking for disallowed parameterization cases.
     */
    if (innerrel->top_parent_relids)
        innerrelids = innerrel->top_parent_relids;
index f7ac71087a6f2192c99d5441dbf29a516ef98835..8dbf790e893e61f4b57366911c7398e30e81026a 100644 (file)
@@ -2360,6 +2360,9 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
  * calc_nestloop_required_outer
  *   Compute the required_outer set for a nestloop join path
  *
+ * Note: when considering a child join, the inputs nonetheless use top-level
+ * parent relids
+ *
  * Note: result must not share storage with either input
  */
 Relids
@@ -2394,11 +2397,30 @@ calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path)
 {
    Relids      outer_paramrels = PATH_REQ_OUTER(outer_path);
    Relids      inner_paramrels = PATH_REQ_OUTER(inner_path);
+   Relids      innerrelids PG_USED_FOR_ASSERTS_ONLY;
+   Relids      outerrelids PG_USED_FOR_ASSERTS_ONLY;
    Relids      required_outer;
 
+   /*
+    * Any parameterization of the input paths refers to topmost parents of
+    * the relevant relations, because reparameterize_path_by_child() hasn't
+    * been called yet.  So we must consider topmost parents of the relations
+    * being joined, too, while checking for disallowed parameterization
+    * cases.
+    */
+   if (inner_path->parent->top_parent_relids)
+       innerrelids = inner_path->parent->top_parent_relids;
+   else
+       innerrelids = inner_path->parent->relids;
+
+   if (outer_path->parent->top_parent_relids)
+       outerrelids = outer_path->parent->top_parent_relids;
+   else
+       outerrelids = outer_path->parent->relids;
+
    /* neither path can require rels from the other */
-   Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
-   Assert(!bms_overlap(inner_paramrels, outer_path->parent->relids));
+   Assert(!bms_overlap(outer_paramrels, innerrelids));
+   Assert(!bms_overlap(inner_paramrels, outerrelids));
    /* form the union ... */
    required_outer = bms_union(outer_paramrels, inner_paramrels);
    /* we do not need an explicit test for empty; bms_union gets it right */