List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:April 14 2011 10:41am
Subject:bzr commit into mysql-5.1 branch (tor.didriksen:3658) Bug#11765713
View as plain text  
#At file:///export/home/didrik/repo/5.1-foo/ based on revid:serge.kozlov@stripped

 3658 Tor Didriksen	2011-04-14
      Bug#11765713 58705: OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES CREATED BY OPT_SUM_QU
      
      Valgrind warnings were caused by comparing index values to an un-initialized field.
     @ mysql-test/r/subselect.result
        New test cases.
     @ mysql-test/t/subselect.test
        New test cases.
     @ sql/opt_sum.cc
        Add thd to opt_sum_query enabling it to test for errors.
        If we have a non-nullable index, we cannot use it to match null values,
        since set_null() will be ignored, and we might compare uninitialized data.
     @ sql/sql_select.cc
        Add thd to opt_sum_query, enabling it to test for errors.
     @ sql/sql_select.h
        Add thd to opt_sum_query, enabling it to test for errors.

    modified:
      mysql-test/r/subselect.result
      mysql-test/t/subselect.test
      sql/opt_sum.cc
      sql/sql_select.cc
      sql/sql_select.h
=== modified file 'mysql-test/r/subselect.result'
--- a/mysql-test/r/subselect.result	2010-11-08 10:55:43 +0000
+++ b/mysql-test/r/subselect.result	2011-04-14 10:41:29 +0000
@@ -4734,3 +4734,21 @@ SELECT * FROM t2 UNION SELECT * FROM t2
 ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE));
 DROP TABLE t1,t2;
 End of 5.1 tests
+#
+# Bug #11765713 58705:
+# OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+# CREATED BY OPT_SUM_QUERY
+#
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1)
+);
+ERROR 21000: Subquery returns more than 1 row
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1 where a is null)
+);
+foo
+DROP TABLE t1;

=== modified file 'mysql-test/t/subselect.test'
--- a/mysql-test/t/subselect.test	2010-11-08 10:55:43 +0000
+++ b/mysql-test/t/subselect.test	2011-04-14 10:41:29 +0000
@@ -3726,3 +3726,25 @@ DROP TABLE t1,t2;
 --enable_result_log
 
 --echo End of 5.1 tests
+
+--echo #
+--echo # Bug #11765713 58705:
+--echo # OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+--echo # CREATED BY OPT_SUM_QUERY
+--echo #
+
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+
+--error ER_SUBQUERY_NO_1_ROW
+SELECT 1 as foo FROM t1 WHERE a < SOME
+  (SELECT a FROM t1 WHERE a <=>
+    (SELECT a FROM t1)
+  );
+
+SELECT 1 as foo FROM t1 WHERE a < SOME
+  (SELECT a FROM t1 WHERE a <=>
+    (SELECT a FROM t1 where a is null)
+  ); 
+
+DROP TABLE t1;

=== modified file 'sql/opt_sum.cc'
--- a/sql/opt_sum.cc	2010-06-11 07:38:29 +0000
+++ b/sql/opt_sum.cc	2011-04-14 10:41:29 +0000
@@ -211,6 +211,7 @@ static int get_index_max_value(TABLE *ta
 /**
   Substitutes constants for some COUNT(), MIN() and MAX() functions.
 
+  @param thd                   thread handler
   @param tables                list of leaves of join table tree
   @param all_fields            All fields to be returned
   @param conds                 WHERE clause
@@ -228,9 +229,12 @@ static int get_index_max_value(TABLE *ta
     HA_ERR_KEY_NOT_FOUND on impossible conditions
   @retval
     HA_ERR_... if a deadlock or a lock wait timeout happens, for example
+  @retval
+    ER_...     e.g. ER_SUBQUERY_NO_1_ROW
 */
 
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
+int opt_sum_query(THD *thd,
+                  TABLE_LIST *tables, List<Item> &all_fields, COND *conds)
 {
   List_iterator_fast<Item> it(all_fields);
   int const_result= 1;
@@ -242,6 +246,8 @@ int opt_sum_query(TABLE_LIST *tables, Li
   Item *item;
   int error;
 
+  DBUG_ENTER("opt_sum_query");
+
   if (conds)
     where_tables= conds->used_tables();
 
@@ -269,7 +275,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
           WHERE t2.field IS NULL;
       */
       if (tl->table->map & where_tables)
-        return 0;
+        DBUG_RETURN(0);
     }
     else
       used_tables|= tl->table->map;
@@ -297,7 +303,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
       {
         tl->table->file->print_error(error, MYF(0));
         tl->table->in_use->fatal_error();
-        return error;
+        DBUG_RETURN(error);
       }
       count*= tl->table->file->stats.records;
     }
@@ -390,10 +396,10 @@ int opt_sum_query(TABLE_LIST *tables, Li
           if (error)
 	  {
 	    if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
-	      return HA_ERR_KEY_NOT_FOUND;	      // No rows matching WHERE
+	      DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); // No rows matching WHERE
 	    /* HA_ERR_LOCK_DEADLOCK or some other error */
  	    table->file->print_error(error, MYF(0));
-            return(error);
+            DBUG_RETURN(error);
 	  }
           removed_tables|= table->map;
         }
@@ -437,6 +443,10 @@ int opt_sum_query(TABLE_LIST *tables, Li
         const_result= 0;
     }
   }
+
+  if (thd->is_error())
+    DBUG_RETURN(thd->main_da.sql_errno());
+
   /*
     If we have a where clause, we can only ignore searching in the
     tables if MIN/MAX optimisation replaced all used tables
@@ -446,7 +456,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
   */
   if (removed_tables && used_tables != removed_tables)
     const_result= 0;                            // We didn't remove all tables
-  return const_result;
+  DBUG_RETURN(const_result);
 }
 
 
@@ -732,6 +742,12 @@ static bool matching_cond(bool max_fl, T
 
     if (is_null || (is_null_safe_eq && args[1]->is_null()))
     {
+      /*
+        If we have a non-nullable index, we cannot use it,
+        since set_null will be ignored, and we will compare uninitialized data.
+      */
+      if (!part->field->maybe_null())
+        DBUG_RETURN(false);
       part->field->set_null();
       *key_ptr= (uchar) 1;
     }
@@ -802,8 +818,9 @@ static bool matching_cond(bool max_fl, T
   @param[out]    prefix_len  Length of prefix for the search range
 
   @note
-    This function may set table->key_read to 1, which must be reset after
-    index is used! (This can only happen when function returns 1)
+    This function may set field->table->key_read to true,
+    which must be reset after index is used!
+    (This can only happen when function returns 1)
 
   @retval
     0   Index can not be used to optimize MIN(field)/MAX(field)
@@ -818,7 +835,9 @@ static bool find_key_for_maxmin(bool max
                                 uint *range_fl, uint *prefix_len)
 {
   if (!(field->flags & PART_KEY_FLAG))
-    return 0;                                        // Not key field
+    return false;                               // Not key field
+
+  DBUG_ENTER("find_key_for_maxmin");
 
   TABLE *table= field->table;
   uint idx= 0;
@@ -843,7 +862,7 @@ static bool find_key_for_maxmin(bool max
          part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
     {
       if (!(table->file->index_flags(idx, jdx, 0) & HA_READ_ORDER))
-        return 0;
+        DBUG_RETURN(false);
 
       /* Check whether the index component is partial */
       Field *part_field= table->field[part->fieldnr-1];
@@ -892,12 +911,12 @@ static bool find_key_for_maxmin(bool max
           */
           if (field->part_of_key.is_set(idx))
             table->set_keyread(TRUE);
-          return 1;
+          DBUG_RETURN(true);
         }
       }
     }
   }
-  return 0;
+  DBUG_RETURN(false);
 }
 
 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2011-02-22 21:03:32 +0000
+++ b/sql/sql_select.cc	2011-04-14 10:41:29 +0000
@@ -961,7 +961,7 @@ JOIN::optimize()
       If all items were resolved by opt_sum_query, there is no need to
       open any tables.
     */
-    if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
+    if ((res=opt_sum_query(thd, select_lex->leaf_tables, all_fields, conds)))
     {
       if (res == HA_ERR_KEY_NOT_FOUND)
       {

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2011-01-07 14:06:24 +0000
+++ b/sql/sql_select.h	2011-04-14 10:41:29 +0000
@@ -612,7 +612,8 @@ Field* create_tmp_field_from_field(THD *
                                                                       
 /* functions from opt_sum.cc */
 bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
+int opt_sum_query(THD* thd,
+                  TABLE_LIST *tables, List<Item> &all_fields, COND *conds);
 
 /* from sql_delete.cc, used by opt_range.cc */
 extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);


Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110414104129-cf9a945ybblyg5w5.bundle
Thread
bzr commit into mysql-5.1 branch (tor.didriksen:3658) Bug#11765713Tor Didriksen14 Apr