List:Commits« Previous MessageNext Message »
From:Roy Lyseng Date:May 6 2010 2:43pm
Subject:bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3138) Bug#38075
View as plain text  
#At file:///home/rl136806/mysql/repo/mysql-next-mr-opt-backporting/ based on revid:oystein.grovlen@stripped

 3138 Roy Lyseng	2010-05-06
      Bug#38075: Wrong result: rows matching a subquery with outer join not returned
        
      The problem is that duplicate weedout handling in evaluate_join_record() is
      incompatible with outer-join condition handling.
      Duplicate weedout checked only the initial predicate, but not the conditional predicates.
      Hence, all the row combinations involving the first row of the innermost
      table that qualified according to the initial predicate would be candidates
      for duplicate elimination. This prevented all row combinations where the
      first row to qualify from the innermost table was not the first row where the
      initial predicate evaluated to true.
      Here, "initial predicate" refers to join_tab->select_cond and "conditional
      predicates" refers to select_cond of "unmatched" join_tabs.
        
      Solved by considering the "found" boolean when performing duplicate elimination.
      Notice also that duplicate elimination now sets "found" instead of exiting
      from routine. This ensures correct book-keeping of e.g examined_rows.
        
      The fix also eliminates one boolean local variable and adds a function header.
        
      mysql-test/r/subselect_sj2.result
        Added test result for bug#38075.
      mysql-test/r/subselect_sj2_jcl6.result
        Added test result for bug#38075.
      mysql-test/t/subselect_sj2.test
        Added test for bug#38075.
      sql/sql_select.cc
        Considers outer-join condition before executing duplicate elimination code.
        Eliminated a boolean variable (select_cond_result).
        Added Doxygen style function header for evaluate_join_record().
      
      original revid: -c3719.1.70

    modified:
      mysql-test/r/subselect_sj.result
      mysql-test/r/subselect_sj_jcl6.result
      mysql-test/t/subselect_sj.test
      sql/sql_select.cc
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result	2010-05-03 12:19:23 +0000
+++ b/mysql-test/r/subselect_sj.result	2010-05-06 14:42:54 +0000
@@ -1121,3 +1121,70 @@ COUNT(*)
 1
 DROP TABLE t1, t2, t3;
 # End of Bug#51487
+# 
+# BUG#38075: Wrong result: rows matching a subquery with outer join not returned
+# 
+DROP TABLE IF EXISTS ot1, it1, it2;
+CREATE TABLE it2 (
+int_key int(11) NOT NULL,
+datetime_key datetime NOT NULL,
+KEY int_key (int_key),
+KEY datetime_key (datetime_key)
+);
+INSERT INTO it2 VALUES
+(5,'2002-04-10 14:25:30'), (0,'0000-00-00 00:00:00'),
+(0,'2006-09-14 04:01:02'), (4,'0000-00-00 00:00:00'),
+(8,'0000-00-00 00:00:00'), (5,'0000-00-00 00:00:00'),
+(9,'0000-00-00 00:00:00'), (8,'2007-04-01 11:04:17'),
+(1,'0000-00-00 00:00:00'), (7,'2009-01-12 00:00:00'),
+(0,'2009-06-05 00:00:00'), (3,'2006-02-14 18:06:35'),
+(5,'2006-02-21 07:08:16'), (0,'0000-00-00 00:00:00'),
+(7,'0000-00-00 00:00:00'), (0,'0000-00-00 00:00:00'),
+(0,'2007-02-13 00:00:00'), (1,'0000-00-00 00:00:00'),
+(0,'0000-00-00 00:00:00'), (1,'2003-08-11 00:00:00');
+CREATE TABLE ot1 (
+int_nokey int(11) NOT NULL,
+int_key int(11) NOT NULL,
+KEY int_key (int_key)
+);
+INSERT INTO ot1 VALUES
+(5,0), (3,0), (0,2), (3,0), (1,3), (0,0), (1,7), (7,0), (1,7), (0,7),
+(0,9), (8,2), (4,4), (9,3), (0,9), (2,5), (0,5), (8,0), (5,8), (1,5);
+CREATE TABLE it1 (
+int_nokey int(11) NOT NULL,
+int_key int(11) NOT NULL,
+KEY int_key (int_key)
+);
+INSERT INTO it1 VALUES
+(9,5), (0,4);
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+int_key
+0
+0
+0
+0
+0
+0
+2
+2
+3
+5
+5
+7
+7
+7
+8
+9
+9
+EXPLAIN
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	it1	index	NULL	int_key	4	NULL	2	Using index; Start temporary
+1	PRIMARY	ot1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+1	PRIMARY	it2	ALL	NULL	NULL	NULL	NULL	20	Using where; End temporary
+DROP TABLE ot1, it1, it2;
+# End of BUG#38075

=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result	2010-05-02 19:14:50 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result	2010-05-06 14:42:54 +0000
@@ -1125,6 +1125,73 @@ COUNT(*)
 1
 DROP TABLE t1, t2, t3;
 # End of Bug#51487
+# 
+# BUG#38075: Wrong result: rows matching a subquery with outer join not returned
+# 
+DROP TABLE IF EXISTS ot1, it1, it2;
+CREATE TABLE it2 (
+int_key int(11) NOT NULL,
+datetime_key datetime NOT NULL,
+KEY int_key (int_key),
+KEY datetime_key (datetime_key)
+);
+INSERT INTO it2 VALUES
+(5,'2002-04-10 14:25:30'), (0,'0000-00-00 00:00:00'),
+(0,'2006-09-14 04:01:02'), (4,'0000-00-00 00:00:00'),
+(8,'0000-00-00 00:00:00'), (5,'0000-00-00 00:00:00'),
+(9,'0000-00-00 00:00:00'), (8,'2007-04-01 11:04:17'),
+(1,'0000-00-00 00:00:00'), (7,'2009-01-12 00:00:00'),
+(0,'2009-06-05 00:00:00'), (3,'2006-02-14 18:06:35'),
+(5,'2006-02-21 07:08:16'), (0,'0000-00-00 00:00:00'),
+(7,'0000-00-00 00:00:00'), (0,'0000-00-00 00:00:00'),
+(0,'2007-02-13 00:00:00'), (1,'0000-00-00 00:00:00'),
+(0,'0000-00-00 00:00:00'), (1,'2003-08-11 00:00:00');
+CREATE TABLE ot1 (
+int_nokey int(11) NOT NULL,
+int_key int(11) NOT NULL,
+KEY int_key (int_key)
+);
+INSERT INTO ot1 VALUES
+(5,0), (3,0), (0,2), (3,0), (1,3), (0,0), (1,7), (7,0), (1,7), (0,7),
+(0,9), (8,2), (4,4), (9,3), (0,9), (2,5), (0,5), (8,0), (5,8), (1,5);
+CREATE TABLE it1 (
+int_nokey int(11) NOT NULL,
+int_key int(11) NOT NULL,
+KEY int_key (int_key)
+);
+INSERT INTO it1 VALUES
+(9,5), (0,4);
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+int_key
+0
+0
+0
+0
+0
+0
+2
+2
+3
+5
+5
+7
+7
+7
+8
+9
+9
+EXPLAIN
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	it1	index	NULL	int_key	4	NULL	2	Using index; Start temporary
+1	PRIMARY	ot1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+1	PRIMARY	it2	ALL	NULL	NULL	NULL	NULL	20	Using where; End temporary; Using join buffer
+DROP TABLE ot1, it1, it2;
+# End of BUG#38075
 set join_cache_level=default;
 show variables like 'join_cache_level';
 Variable_name	Value

=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test	2010-04-15 11:23:42 +0000
+++ b/mysql-test/t/subselect_sj.test	2010-05-06 14:42:54 +0000
@@ -816,3 +816,54 @@ DROP TABLE t1, t2, t3;
 
 --echo # End of Bug#51487
 
+--echo # 
+--echo # BUG#38075: Wrong result: rows matching a subquery with outer join not returned
+--echo # 
+
+--disable_warnings
+DROP TABLE IF EXISTS ot1, it1, it2;
+--enable_warnings
+
+CREATE TABLE it2 (
+  int_key int(11) NOT NULL,
+  datetime_key datetime NOT NULL,
+  KEY int_key (int_key),
+  KEY datetime_key (datetime_key)
+);
+INSERT INTO it2 VALUES
+  (5,'2002-04-10 14:25:30'), (0,'0000-00-00 00:00:00'),
+  (0,'2006-09-14 04:01:02'), (4,'0000-00-00 00:00:00'),
+  (8,'0000-00-00 00:00:00'), (5,'0000-00-00 00:00:00'),
+  (9,'0000-00-00 00:00:00'), (8,'2007-04-01 11:04:17'),
+  (1,'0000-00-00 00:00:00'), (7,'2009-01-12 00:00:00'),
+  (0,'2009-06-05 00:00:00'), (3,'2006-02-14 18:06:35'),
+  (5,'2006-02-21 07:08:16'), (0,'0000-00-00 00:00:00'),
+  (7,'0000-00-00 00:00:00'), (0,'0000-00-00 00:00:00'),
+  (0,'2007-02-13 00:00:00'), (1,'0000-00-00 00:00:00'),
+  (0,'0000-00-00 00:00:00'), (1,'2003-08-11 00:00:00');
+CREATE TABLE ot1 (
+  int_nokey int(11) NOT NULL,
+  int_key int(11) NOT NULL,
+  KEY int_key (int_key)
+);
+INSERT INTO ot1 VALUES
+  (5,0), (3,0), (0,2), (3,0), (1,3), (0,0), (1,7), (7,0), (1,7), (0,7),
+  (0,9), (8,2), (4,4), (9,3), (0,9), (2,5), (0,5), (8,0), (5,8), (1,5);
+CREATE TABLE it1 (
+  int_nokey int(11) NOT NULL,
+  int_key int(11) NOT NULL,
+  KEY int_key (int_key)
+);
+INSERT INTO it1 VALUES
+  (9,5), (0,4);
+--sorted_result
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+                    FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+EXPLAIN
+SELECT int_key FROM ot1
+WHERE int_nokey IN (SELECT it2.int_key
+                    FROM it1 LEFT JOIN it2 ON it2.datetime_key);
+DROP TABLE ot1, it1, it2;
+
+--echo # End of BUG#38075

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-05-06 13:50:15 +0000
+++ b/sql/sql_select.cc	2010-05-06 14:42:54 +0000
@@ -16579,11 +16579,18 @@ int do_sj_reset(SJ_TMP_TABLE *sj_tbl)
 }
 
 /**
-  Process one record of the nested loop join.
+  @brief Process one row of the nested loop join.
 
-    This function will evaluate parts of WHERE/ON clauses that are
-    applicable to the partial record on hand and in case of success
-    submit this record to the next level of the nested loop.
+  This function will evaluate parts of WHERE/ON clauses that are
+  applicable to the partial row on hand and in case of success
+  submit this row to the next level of the nested loop.
+
+  @param  join     - The join object
+  @param  join_tab - The most inner join_tab being processed
+  @param  error > 0: Error, terminate processing
+                = 0: (Partial) row is available
+                < 0: No more rows available at this level
+  @return Nested loop state (Ok, No_more_rows, Error, Killed)
 */
 
 static enum_nested_loop_state
@@ -16593,7 +16600,7 @@ evaluate_join_record(JOIN *join, JOIN_TA
   bool not_used_in_distinct=join_tab->not_used_in_distinct;
   ha_rows found_records=join->found_records;
   COND *select_cond= join_tab->select_cond;
-  bool select_cond_result= TRUE;
+  bool found= TRUE;
 
   DBUG_ENTER("evaluate_join_record");
 
@@ -16610,20 +16617,18 @@ evaluate_join_record(JOIN *join, JOIN_TA
 
   if (select_cond)
   {
-    select_cond_result= test(select_cond->val_int());
+    found= test(select_cond->val_int());
 
     /* check for errors evaluating the condition */
     if (join->thd->is_error())
       DBUG_RETURN(NESTED_LOOP_ERROR);
   }
-
-  if (!select_cond || select_cond_result)
+  if (found)
   {
     /*
       There is no select condition or the attached pushed down
       condition is true => a match is found.
     */
-    bool found= 1;
     while (join_tab->first_unmatched && found)
     {
       /*
@@ -16675,13 +16680,14 @@ evaluate_join_record(JOIN *join, JOIN_TA
 
     JOIN_TAB *return_tab= join->return_tab;
     join_tab->found_match= TRUE;
-    if (join_tab->check_weed_out_table)
+
+    if (join_tab->check_weed_out_table && found)
     {
       int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table);
       if (res == -1)
         DBUG_RETURN(NESTED_LOOP_ERROR);
-      if (res == 1)
-        DBUG_RETURN(NESTED_LOOP_OK);
+      else if (res == 1)
+        found= FALSE;
     }
     else if (join_tab->do_firstmatch)
     {


Attachment: [text/bzr-bundle] bzr/roy.lyseng@sun.com-20100506144254-uuq5pedv1pr9dc3p.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3138) Bug#38075Roy Lyseng6 May