List:Commits« Previous MessageNext Message »
From:timour Date:October 24 2007 1:11pm
Subject:bk commit into 5.2 tree (timour:1.2616)
View as plain text  
Below is the list of changes that have just been committed into a local
5.2 repository of tkatchaounov. When tkatchaounov does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-10-24 16:11:27+03:00, timour@stripped +4 -0
  There were two distinct problems in this bug:
  1. At execution time the subquery under an IN predicate was optimized with
     the global memeber thd->lex->current_select pointing to the outer select.
     This caused the subquery to be optimized differently when
     JOIN::optimize needed to analyze current_select.
  
     Fixed by setting the correct current_select for the optimization
     and execution (materialization) of the subquery.
  2. When running EXPLAIN, optimization took a different path because
     - Item_exists_subselect::fix_length_and_dec sets the subquery
       LIMIT to 1, then
     - mysql_explain_union(), which is called only for EXPLAIN called
       unit->set_limit(unit->global_parameters), which resets
       join->unit->select_limit_cnt to 1, this in turn
     - affected make_join_select to call sel->test_quick_select, which
       deleted the quick_select access method.
     Fixed by setting the limit correctly when IN is executed via
     materialization.

  mysql-test/r/subselect_mat.result@stripped, 2007-10-24 16:11:13+03:00, timour@stripped +59 -3
    Test for BUG#31639.

  mysql-test/t/subselect_mat.test@stripped, 2007-10-24 16:11:14+03:00, timour@stripped +39 -1
    Test for BUG#31639.

  sql/item_subselect.cc@stripped, 2007-10-24 16:11:15+03:00, timour@stripped +23 -4
    - reset the LIMIT for the subquery to inifinity if it will be materialized.
    - set and restore the correct thd->lex->current_select around the optimization
      and materialization of the subquery. 

  sql/sql_lex.cc@stripped, 2007-10-24 16:11:16+03:00, timour@stripped +16 -8
    Update the ASSERT to reflect that with materialization we set the LIMIT
    to infinity.

diff -Nrup a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result
--- a/mysql-test/r/subselect_mat.result	2007-10-18 17:50:27 +03:00
+++ b/mysql-test/r/subselect_mat.result	2007-10-24 16:11:13 +03:00
@@ -1,4 +1,4 @@
-drop table if exists t1, t2, t3;
+drop table if exists t1, t2, t3, t1i, t2i, t3i;
 create table t1 (a1 char(8), a2 char(8));
 create table t2 (b1 char(8), b2 char(8));
 create table t3 (c1 char(8), c2 char(8));
@@ -6,18 +6,74 @@ insert into t1 values ('1 - 00', '2 - 00
 insert into t1 values ('1 - 01', '2 - 01');
 insert into t1 values ('1 - 02', '2 - 02');
 insert into t2 values ('1 - 01', '2 - 01');
+insert into t2 values ('1 - 01', '2 - 01');
+insert into t2 values ('1 - 02', '2 - 02');
 insert into t2 values ('1 - 02', '2 - 02');
 insert into t2 values ('1 - 03', '2 - 03');
 insert into t3 values ('1 - 01', '2 - 01');
 insert into t3 values ('1 - 02', '2 - 02');
 insert into t3 values ('1 - 03', '2 - 03');
 insert into t3 values ('1 - 04', '2 - 04');
+create table t1i (a1 char(8), a2 char(8));
+create table t2i (b1 char(8), b2 char(8));
+create table t3i (c1 char(8), c2 char(8));
+create index it1i1 on t1i (a1);
+create index it1i2 on t1i (a2);
+create index it1i3 on t1i (a1, a2);
+create index it2i1 on t2i (b1);
+create index it2i2 on t2i (b2);
+create index it2i3 on t2i (b1, b2);
+create index it3i1 on t3i (c1);
+create index it3i2 on t3i (c2);
+create index it3i3 on t3i (c1, c2);
+insert into t1i select * from t1;
+insert into t2i select * from t2;
+insert into t3i select * from t3;
 set @@optimizer_switch=no_semijoin;
 /******************************************************************************
 * Simple tests.                                                               *
 ******************************************************************************/
-# test re-optimization/re-execution with different execution methods
-# prepare once, exec with different modes
+# BUG#31639: Wrong plan for uncorrelated subquery when loose scan is applicable.
+explain extended
+select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
+2	SUBQUERY	t2i	range	NULL	it2i3	9	NULL	3	100.00	Using index for group-by
+Warnings:
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,max(`test`.`t2i`.`b2`) AS `max(b2)` from `test`.`t2i` group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1);
+a1	a2
+1 - 01	2 - 01
+1 - 02	2 - 02
+prepare st1 from "explain select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)";
+execute st1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where
+2	SUBQUERY	t2i	range	NULL	it2i3	9	NULL	3	Using index for group-by
+execute st1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where
+2	SUBQUERY	t2i	range	NULL	it2i3	9	NULL	3	Using index for group-by
+prepare st2 from "select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)";
+execute st2;
+a1	a2
+1 - 01	2 - 01
+1 - 02	2 - 02
+execute st2;
+a1	a2
+1 - 01	2 - 01
+1 - 02	2 - 02
+explain extended
+select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
+2	SUBQUERY	t2i	range	it2i1,it2i3	it2i3	18	NULL	3	100.00	Using where; Using index for group-by
+Warnings:
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,min(`test`.`t2i`.`b2`) AS `min(b2)` from `test`.`t2i` where (`test`.`t2i`.`b1` > _latin1'0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
+a1	a2
+1 - 01	2 - 01
+1 - 02	2 - 02
 set @@optimizer_switch=no_materialization;
 set @@optimizer_switch=no_semijoin;
 /******************************************************************************
diff -Nrup a/mysql-test/t/subselect_mat.test b/mysql-test/t/subselect_mat.test
--- a/mysql-test/t/subselect_mat.test	2007-10-18 17:50:27 +03:00
+++ b/mysql-test/t/subselect_mat.test	2007-10-24 16:11:14 +03:00
@@ -4,7 +4,7 @@
 #
 
 --disable_warnings
-drop table if exists t1, t2, t3;
+drop table if exists t1, t2, t3, t1i, t2i, t3i;
 --enable_warnings
 
 create table t1 (a1 char(8), a2 char(8));
@@ -16,6 +16,8 @@ insert into t1 values ('1 - 01', '2 - 01
 insert into t1 values ('1 - 02', '2 - 02');
 
 insert into t2 values ('1 - 01', '2 - 01');
+insert into t2 values ('1 - 01', '2 - 01');
+insert into t2 values ('1 - 02', '2 - 02');
 insert into t2 values ('1 - 02', '2 - 02');
 insert into t2 values ('1 - 03', '2 - 03');
 
@@ -24,12 +26,48 @@ insert into t3 values ('1 - 02', '2 - 02
 insert into t3 values ('1 - 03', '2 - 03');
 insert into t3 values ('1 - 04', '2 - 04');
 
+# Indexed columns
+create table t1i (a1 char(8), a2 char(8));
+create table t2i (b1 char(8), b2 char(8));
+create table t3i (c1 char(8), c2 char(8));
+create index it1i1 on t1i (a1);
+create index it1i2 on t1i (a2);
+create index it1i3 on t1i (a1, a2);
+
+create index it2i1 on t2i (b1);
+create index it2i2 on t2i (b2);
+create index it2i3 on t2i (b1, b2);
+
+create index it3i1 on t3i (c1);
+create index it3i2 on t3i (c2);
+create index it3i3 on t3i (c1, c2);
+
+insert into t1i select * from t1;
+insert into t2i select * from t2;
+insert into t3i select * from t3;
+
 # force the use of materialization
 set @@optimizer_switch=no_semijoin;
 
 /******************************************************************************
 * Simple tests.                                                               *
 ******************************************************************************/
+
+# BUG#31639: Wrong plan for uncorrelated subquery when loose scan is applicable.
+explain extended
+select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1);
+select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1);
+
+prepare st1 from "explain select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)";
+execute st1;
+execute st1;
+prepare st2 from "select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1)";
+execute st2;
+execute st2;
+
+explain extended
+select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
+select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
 
 # test re-optimization/re-execution with different execution methods
 # prepare once, exec with different modes
diff -Nrup a/sql/item_subselect.cc b/sql/item_subselect.cc
--- a/sql/item_subselect.cc	2007-10-18 17:50:27 +03:00
+++ b/sql/item_subselect.cc	2007-10-24 16:11:15 +03:00
@@ -1798,8 +1798,16 @@ bool Item_in_subselect::setup_engine()
   }
 
   /* Initilizations done in runtime memory, repeated for each execution. */
-  if (new_engine && (res= new_engine->init_runtime()))
-    DBUG_RETURN(res);
+  if (new_engine)
+  {
+    /*
+      With materialization there is no limit on the materialized subquery.
+      Reset the limit that was set in Item_exists_subselect::fix_length_and_dec.
+    */
+    unit->global_parameters->select_limit= NULL;
+    if ((res= new_engine->init_runtime()))
+      DBUG_RETURN(res);
+  }
 
   DBUG_RETURN(res);
 }
@@ -3121,9 +3129,15 @@ int subselect_hash_sj_engine::exec()
   */
   if (!is_materialized)
   {
-    if (materialize_join->optimize())
-      DBUG_RETURN(TRUE);     
+    int res= 0;
+    SELECT_LEX *save_select= thd->lex->current_select;
+    thd->lex->current_select= materialize_engine->select_lex;
+    if ((res= materialize_join->optimize()))
+      goto err;
     materialize_join->exec();
+    if ((res= test(materialize_join->error || thd->is_fatal_error)))
+      goto err;
+
     /*
       TODO:
       - Unlock all subquery tables as we don't need them. To implement this
@@ -3152,6 +3166,11 @@ int subselect_hash_sj_engine::exec()
     tmp_param= &(item_in->unit->outer_select()->join->tmp_table_param);
     if (tmp_param && !tmp_param->copy_field)
       tmp_param= NULL;
+
+err:
+    thd->lex->current_select= save_select;
+    if (res)
+      DBUG_RETURN(res);
   }
 
   /*
diff -Nrup a/sql/sql_lex.cc b/sql/sql_lex.cc
--- a/sql/sql_lex.cc	2007-10-18 17:50:28 +03:00
+++ b/sql/sql_lex.cc	2007-10-24 16:11:16 +03:00
@@ -2007,16 +2007,24 @@ void st_select_lex::print_limit(THD *thd
 {
   SELECT_LEX_UNIT *unit= master_unit();
   Item_subselect *item= unit->item;
-  if (item && unit->global_parameters == this &&
-      (item->substype() == Item_subselect::EXISTS_SUBS ||
-       item->substype() == Item_subselect::IN_SUBS ||
-       item->substype() == Item_subselect::ALL_SUBS))
+
+  if (item && unit->global_parameters == this)
   {
-    DBUG_ASSERT(!item->fixed ||
-                select_limit->val_int() == LL(1) && offset_limit == 0);
-    return;
+    Item_subselect::subs_type subs_type= item->substype();
+    if (subs_type == Item_subselect::EXISTS_SUBS ||
+        subs_type == Item_subselect::IN_SUBS ||
+        subs_type == Item_subselect::ALL_SUBS)
+    {
+      DBUG_ASSERT(!item->fixed ||
+                  /* select_limit should be 1 only if not using materialization */
+                  (((subs_type == Item_subselect::IN_SUBS) &&
+                    ((Item_in_subselect*)item)->exec_method ==
+                    Item_in_subselect::MATERIALIZATION) ?
+                   TRUE : select_limit->val_int() == LL(1)) &&
+                  offset_limit == 0);
+      return;
+    }
   }
-
   if (explicit_limit)
   {
     str->append(STRING_WITH_LEN(" limit "));
Thread
bk commit into 5.2 tree (timour:1.2616)timour24 Oct