]> granicus.if.org Git - postgresql/commitdiff
Fix a thinko in join_is_legal: when we decide we can implement a semijoin
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 19 Jul 2009 20:32:48 +0000 (20:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 19 Jul 2009 20:32:48 +0000 (20:32 +0000)
by unique-ifying the RHS and then inner-joining to some other relation,
that is not grounds for violating the RHS of some other outer join.
Noticed while regression-testing new GEQO code, which will blindly follow
any path that join_is_legal says is legal, and then complain later if that
leads to a dead end.

I'm not certain that this can result in any visible failure in 8.4: the
mistake may always be masked by the fact that subsequent attempts to join
the rest of the RHS of the other join will fail.  But I'm not certain it
can't, either, and it's definitely not operating as intended.  So back-patch.

The added regression test depends on the new no-failures-allowed logic
that I'm about to commit in GEQO, so no point back-patching that.

src/backend/optimizer/path/joinrels.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 9e6f57f4c9e5339b8a7ac4543591797a4fca9365..350fde29c21f78cf73d5e89412b6f58bd843c064 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.100 2009/06/11 14:48:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.101 2009/07/19 20:32:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -349,6 +349,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 {
        SpecialJoinInfo *match_sjinfo;
        bool            reversed;
+       bool            unique_ified;
        bool            is_valid_inner;
        ListCell   *l;
 
@@ -366,6 +367,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
         */
        match_sjinfo = NULL;
        reversed = false;
+       unique_ified = false;
        is_valid_inner = true;
 
        foreach(l, root->join_info_list)
@@ -450,6 +452,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                return false;   /* invalid join path */
                        match_sjinfo = sjinfo;
                        reversed = false;
+                       unique_ified = true;
                }
                else if (sjinfo->jointype == JOIN_SEMI &&
                                 bms_equal(sjinfo->syn_righthand, rel1->relids) &&
@@ -461,6 +464,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                return false;   /* invalid join path */
                        match_sjinfo = sjinfo;
                        reversed = true;
+                       unique_ified = true;
                }
                else
                {
@@ -510,8 +514,13 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                }
        }
 
-       /* Fail if violated some SJ's RHS and didn't match to another SJ */
-       if (match_sjinfo == NULL && !is_valid_inner)
+       /*
+        * Fail if violated some SJ's RHS and didn't match to another SJ.
+        * However, "matching" to a semijoin we are implementing by
+        * unique-ification doesn't count (think: it's really an inner join).
+        */
+       if (!is_valid_inner &&
+               (match_sjinfo == NULL || unique_ified))
                return false;                   /* invalid join path */
 
        /* Otherwise, it's a valid join */
index a7b7b73ad6f13095653a9b2104690b0d808b2406..afb4f974e7a252074bdfa4b1d8de733debb2a1f4 100644 (file)
@@ -2150,6 +2150,20 @@ select count(*) from tenk1 x where
      1
 (1 row)
 
+-- try that with GEQO too
+begin;
+set geqo = on;
+set geqo_threshold = 2;
+select count(*) from tenk1 x where
+  x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and
+  x.unique1 = 0 and
+  x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
+ count 
+-------
+     1
+(1 row)
+
+rollback;
 --
 -- Clean up
 --
index 29992ced0c230bf7d7b81bac0f22919b14096791..123d1f3015daba2cd402194f7d8f822d82c28c20 100644 (file)
@@ -343,6 +343,16 @@ select count(*) from tenk1 x where
   x.unique1 = 0 and
   x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
 
+-- try that with GEQO too
+begin;
+set geqo = on;
+set geqo_threshold = 2;
+select count(*) from tenk1 x where
+  x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and
+  x.unique1 = 0 and
+  x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
+rollback;
+
 
 --
 -- Clean up