Handle SubPlan cases in find_nonnullable_rels/vars.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Nov 2022 19:24:36 +0000 (15:24 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Nov 2022 19:24:36 +0000 (15:24 -0400)
We can use some variants of SubPlan to deduce that Vars appearing
in the testexpr must be non-null.

Richard Guo

Discussion: https://postgr.es/m/CAMbWs4-jV=199A2Y_6==99dYnpnmaO_Wz_RGkRTTaCB=Pihw2w@mail.gmail.com

src/backend/optimizer/util/clauses.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 7fb32a071030955ef30af8a9abd0c6f8b8b63fb5..5e791333cbd6d72b46d7960199e1376538197fa9 100644 (file)
@@ -1511,6 +1511,31 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
             expr->booltesttype == IS_NOT_UNKNOWN))
            result = find_nonnullable_rels_walker((Node *) expr->arg, false);
    }
+   else if (IsA(node, SubPlan))
+   {
+       SubPlan    *splan = (SubPlan *) node;
+
+       /*
+        * For some types of SubPlan, we can infer strictness from Vars in the
+        * testexpr (the LHS of the original SubLink).
+        *
+        * For ANY_SUBLINK, if the subquery produces zero rows, the result is
+        * always FALSE.  If the subquery produces more than one row, the
+        * per-row results of the testexpr are combined using OR semantics.
+        * Hence ANY_SUBLINK can be strict only at top level, but there it's
+        * as strict as the testexpr is.
+        *
+        * For ROWCOMPARE_SUBLINK, if the subquery produces zero rows, the
+        * result is always NULL.  Otherwise, the result is as strict as the
+        * testexpr is.  So we can check regardless of top_level.
+        *
+        * We can't prove anything for other sublink types (in particular,
+        * note that ALL_SUBLINK will return TRUE if the subquery is empty).
+        */
+       if ((top_level && splan->subLinkType == ANY_SUBLINK) ||
+           splan->subLinkType == ROWCOMPARE_SUBLINK)
+           result = find_nonnullable_rels_walker(splan->testexpr, top_level);
+   }
    else if (IsA(node, PlaceHolderVar))
    {
        PlaceHolderVar *phv = (PlaceHolderVar *) node;
@@ -1736,6 +1761,15 @@ find_nonnullable_vars_walker(Node *node, bool top_level)
             expr->booltesttype == IS_NOT_UNKNOWN))
            result = find_nonnullable_vars_walker((Node *) expr->arg, false);
    }
+   else if (IsA(node, SubPlan))
+   {
+       SubPlan    *splan = (SubPlan *) node;
+
+       /* See analysis in find_nonnullable_rels_walker */
+       if ((top_level && splan->subLinkType == ANY_SUBLINK) ||
+           splan->subLinkType == ROWCOMPARE_SUBLINK)
+           result = find_nonnullable_vars_walker(splan->testexpr, top_level);
+   }
    else if (IsA(node, PlaceHolderVar))
    {
        PlaceHolderVar *phv = (PlaceHolderVar *) node;
index b901d7299fad00e6310edc3bcae0b5329510b6e7..93583710725b0a075edbcf782eb5ef395e7c5d10 100644 (file)
@@ -4650,6 +4650,34 @@ select a.q2, b.q1
 
 reset enable_hashjoin;
 reset enable_nestloop;
+--
+-- test join strength reduction with a SubPlan providing the proof
+--
+explain (costs off)
+select a.unique1, b.unique2
+  from onek a left join onek b on a.unique1 = b.unique2
+  where b.unique2 = any (select q1 from int8_tbl c where c.q1 < b.unique1);
+                        QUERY PLAN                        
+----------------------------------------------------------
+ Hash Join
+   Hash Cond: (b.unique2 = a.unique1)
+   ->  Seq Scan on onek b
+         Filter: (SubPlan 1)
+         SubPlan 1
+           ->  Seq Scan on int8_tbl c
+                 Filter: (q1 < b.unique1)
+   ->  Hash
+         ->  Index Only Scan using onek_unique1 on onek a
+(9 rows)
+
+select a.unique1, b.unique2
+  from onek a left join onek b on a.unique1 = b.unique2
+  where b.unique2 = any (select q1 from int8_tbl c where c.q1 < b.unique1);
+ unique1 | unique2 
+---------+---------
+     123 |     123
+(1 row)
+
 --
 -- test join removal
 --
index ccbbe5454c5bd09d82dc735191b92bdede1d5b46..a81c7dce7d55ac8587c505f9e2fd6316e93b72d5 100644 (file)
@@ -1603,6 +1603,19 @@ select a.q2, b.q1
 reset enable_hashjoin;
 reset enable_nestloop;
 
+--
+-- test join strength reduction with a SubPlan providing the proof
+--
+
+explain (costs off)
+select a.unique1, b.unique2
+  from onek a left join onek b on a.unique1 = b.unique2
+  where b.unique2 = any (select q1 from int8_tbl c where c.q1 < b.unique1);
+
+select a.unique1, b.unique2
+  from onek a left join onek b on a.unique1 = b.unique2
+  where b.unique2 = any (select q1 from int8_tbl c where c.q1 < b.unique1);
+
 --
 -- test join removal
 --