List:Commits« Previous MessageNext Message »
From:Martin Hansson Date:August 7 2009 8:23am
Subject:bzr commit into mysql-5.1-bugteam branch (martin.hansson:3062) Bug#46454
View as plain text  
#At file:///data0/martin/bzr/bug46454/5.1bt-gca/ based on revid:davi.arnaut@stripped

 3062 Martin Hansson	2009-08-07
      Bug#46454: MySQL wrong index optimisation leads to incorrect result & crashes
      
      When the 'Using index' optimization is used, the optimizer may still - after
      cost-based optimization - decide to use another index in order to avoid using
      a temporary table. But when this happens, the flag to the storage engine to 
      read index only (not table) was still set. Fixed by resetting the flag in the 
      storage engine and TABLE structure in the above scenario, unless the new index
      allows for the same optimization.
     @ mysql-test/r/order_by.result
        Bug#46454: Test result.
     @ mysql-test/t/order_by.test
        Bug#46454: Test case.
     @ sql/sql_select.cc
        Bug#46454: Fix. Removed code which would be a duplicate.
     @ sql/table.h
        Bug#46454: Added comment to field.

    modified:
      mysql-test/r/order_by.result
      mysql-test/t/order_by.test
      sql/sql_select.cc
      sql/table.h
=== modified file 'mysql-test/r/order_by.result'
--- a/mysql-test/r/order_by.result	2008-10-16 18:04:31 +0000
+++ b/mysql-test/r/order_by.result	2009-08-07 08:23:40 +0000
@@ -1500,3 +1500,39 @@ id1
 15
 16
 DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT, c char(100), KEY (b, c), KEY (b, a, c))
+DEFAULT CHARSET = utf8;
+INSERT INTO t1 VALUES 
+(1,  1, 1),
+(2,  2, 2),
+(3,  3, 3),
+(4,  4, 4),
+(5,  5, 5),
+(6,  6, 6),
+(7,  7, 7),
+(8,  8, 8),
+(9,  9, 9);
+INSERT INTO t1 SELECT a + 10,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 20,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 40,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 80,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 160, b, c FROM t1;
+INSERT INTO t1 SELECT a + 320, b, c FROM t1;
+INSERT INTO t1 SELECT a + 640, b, c FROM t1;
+INSERT INTO t1 SELECT a + 640, b, c FROM t1;
+EXPLAIN
+SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	range	b,b_2	b	5	NULL	226	Using where
+SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9;
+a
+1911
+1901
+1891
+1881
+1871
+1861
+1851
+1841
+1831
+DROP TABLE t1;

=== modified file 'mysql-test/t/order_by.test'
--- a/mysql-test/t/order_by.test	2008-10-16 18:04:31 +0000
+++ b/mysql-test/t/order_by.test	2009-08-07 08:23:40 +0000
@@ -1361,3 +1361,34 @@ DROP TABLE t1;
 
 
 
+#
+# Bug#46454: MySQL wrong index optimisation leads to incorrect result & crashes 
+#
+CREATE TABLE t1 (a INT, b INT, c char(100), KEY (b, c), KEY (b, a, c))
+DEFAULT CHARSET = utf8;
+
+INSERT INTO t1 VALUES 
+(1,  1, 1),
+(2,  2, 2),
+(3,  3, 3),
+(4,  4, 4),
+(5,  5, 5),
+(6,  6, 6),
+(7,  7, 7),
+(8,  8, 8),
+(9,  9, 9);
+
+INSERT INTO t1 SELECT a + 10,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 20,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 40,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 80,  b, c FROM t1;
+INSERT INTO t1 SELECT a + 160, b, c FROM t1;
+INSERT INTO t1 SELECT a + 320, b, c FROM t1;
+INSERT INTO t1 SELECT a + 640, b, c FROM t1;
+INSERT INTO t1 SELECT a + 640, b, c FROM t1;
+
+EXPLAIN
+SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9;
+SELECT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 9;
+
+DROP TABLE t1;

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-07-24 12:15:56 +0000
+++ b/sql/sql_select.cc	2009-08-07 08:23:40 +0000
@@ -12946,6 +12946,8 @@ find_field_in_item_list (Field *field, v
 
   The index must cover all fields in <order>, or it will not be considered.
 
+  @param no_changes No changes will be made to the query plan.
+
   @todo
     - sergeyp: Results of all index merge selects actually are ordered 
     by clustered PK values.
@@ -13280,6 +13282,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
       }
       if (!no_changes)
       {
+        /* 
+           If ref_key used index tree reading only ('Using index' in EXPLAIN),
+           and best_key doesn't, then revert the decision.
+        */
+        if (!table->covering_keys.is_set(best_key) && table->key_read)
+        {
+          table->key_read= 0;
+          table->file->extra(HA_EXTRA_NO_KEYREAD);          
+        }        
         if (!quick_created)
 	{
           tab->index= best_key;
@@ -13296,16 +13307,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
             table->key_read=1;
             table->file->extra(HA_EXTRA_KEYREAD);
           }
-          else if (table->key_read)
-          {
-            /*
-              Clear the covering key read flags that might have been
-              previously set for some key other than the current best_key.
-            */
-            table->key_read= 0;
-            table->file->extra(HA_EXTRA_NO_KEYREAD);
-          }
-
           table->file->ha_index_or_rnd_end();
           if (join->select_options & SELECT_DESCRIBE)
           {

=== modified file 'sql/table.h'
--- a/sql/table.h	2009-07-29 08:54:20 +0000
+++ b/sql/table.h	2009-08-07 08:23:40 +0000
@@ -755,7 +755,13 @@ struct st_table {
   */
   my_bool force_index;
   my_bool distinct,const_table,no_rows;
-  my_bool key_read, no_keyread;
+
+  /**
+     If set, the optimizer has found that row retrieval should access index 
+     tree only.
+   */
+  my_bool key_read;
+  my_bool no_keyread;
   /*
     Placeholder for an open table which prevents other connections
     from taking name-locks on this table. Typically used with


Attachment: [text/bzr-bundle] bzr/martin.hansson@sun.com-20090807082340-fz1tlslbj0rkoiwo.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (martin.hansson:3062) Bug#46454Martin Hansson7 Aug