List:Commits« Previous MessageNext Message »
From:Norvald H. Ryeng Date:January 16 2012 9:02am
Subject:bzr push into mysql-trunk branch (norvald.ryeng:3730 to 3731) Bug#11766143
View as plain text  
 3731 Norvald H. Ryeng	2012-01-16
      Bug#11766143 59185: ASSERTION FAILED: (FIXED == 1), FILE
      ITEM_STRFUNC.CC, LINE 2760
      
      Problem: The server crashes when a subquery that is involved in a
      comparison requiring a character set conversion causes an error.
      
      During optimization, predicates are combined into multiple equality
      predicates by a call to optimize_cond(). As part of this,
      Item_equal::compare_const() is called to evaluate the comparison. Part
      of this evaluation is to set the comparison function by a call to
      Item_func_eq::set_cmp_func(), which calls
      Arg_comparator::set_cmp_func(). Since the character sets of the two
      arguments differ, it needs to call agg_item_set_converter() to set up
      a conversion. There, a new Item_func_conv_charset is constructed, and
      the constructor calls val_str() on its argument (the subquery). The
      subquery is evaluated and stores an error in the diagnostics
      area.
      
      Later, agg_item_set_converter() calls fix_fields() on the character
      set converter. Item_func::fix_fields() checks for thd->is_error() and
      misinterprets the error as if it occurred in
      Item_func::fix_length_and_dec(). This error is propagated by return
      values back to Arg_comparator::set_cmp_func(), which therefore skips
      setting the func attribute of the comparator.
      
      After the error occurs, Item_equal::compare_const() does not do any
      error checking before calling Item_func_eq::val_int(), where the crash
      occurs when Arg_comparator::compare() tries to call the function
      pointed to by the func attribute, which is a null pointer.
      
      Fix: Skip the call to Item_func_eq::val_int() in
      Item_equal::compare_const() if an error has been stored in the
      diagnostics area. The diagnostics area is checked and the error is
      caught in JOIN::optimize() right after the call to optimize_cond()
      returns.
      
      This patch also fixes bug #11765734.
     @ mysql-test/r/ctype_many.result
        Add test for bug #11766143.
     @ mysql-test/t/ctype_many.test
        Add test for bug #11766143.
     @ sql/item_cmpfunc.cc
        Skip condition evaluation if an error has occurred.
     @ sql/item_cmpfunc.h
        Add return value to Item_bool_func2::set_cmp_func().
     @ sql/sql_optimizer.cc
        Add error handling.

    modified:
      mysql-test/r/ctype_many.result
      mysql-test/t/ctype_many.test
      sql/item_cmpfunc.cc
      sql/item_cmpfunc.h
      sql/sql_optimizer.cc
 3730 Marko Mäkelä	2012-01-16 [merge]
      Merge mysql-5.5 to mysql-trunk.

    modified:
      storage/innobase/buf/buf0buf.cc
=== modified file 'mysql-test/r/ctype_many.result'
--- a/mysql-test/r/ctype_many.result	2011-01-17 12:26:13 +0000
+++ b/mysql-test/r/ctype_many.result	2012-01-16 09:01:53 +0000
@@ -1776,3 +1776,14 @@ DROP TABLE t2;
 #
 # End of 5.5 tests
 #
+#
+# Bug#11766143 59185: ASSERTION FAILED: (FIXED == 1), FILE
+# ITEM_STRFUNC.CC, LINE 2760
+#
+CREATE TABLE t1 (a CHAR(1) CHARSET UTF8);
+INSERT INTO t1 VALUES ('a'), ('b');
+CREATE TABLE t2 (a BINARY(1));
+SELECT * FROM t2 WHERE a=(SELECT a FROM t1) AND a=_LATIN1'x';
+ERROR 21000: Subquery returns more than 1 row
+DROP TABLE t2;
+DROP TABLE t1;

=== modified file 'mysql-test/t/ctype_many.test'
--- a/mysql-test/t/ctype_many.test	2011-01-17 12:26:13 +0000
+++ b/mysql-test/t/ctype_many.test	2012-01-16 09:01:53 +0000
@@ -319,3 +319,15 @@ DROP TABLE t2;
 --echo #
 --echo # End of 5.5 tests
 --echo #
+
+--echo #
+--echo # Bug#11766143 59185: ASSERTION FAILED: (FIXED == 1), FILE
+--echo # ITEM_STRFUNC.CC, LINE 2760
+--echo #
+CREATE TABLE t1 (a CHAR(1) CHARSET UTF8);
+INSERT INTO t1 VALUES ('a'), ('b');
+CREATE TABLE t2 (a BINARY(1));
+--error ER_SUBQUERY_NO_1_ROW
+SELECT * FROM t2 WHERE a=(SELECT a FROM t1) AND a=_LATIN1'x';
+DROP TABLE t2;
+DROP TABLE t1;

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2012-01-12 13:22:52 +0000
+++ b/sql/item_cmpfunc.cc	2012-01-16 09:01:53 +0000
@@ -5987,7 +5987,8 @@ void Item_equal::compare_const(Item *c)
   else
   {
     Item_func_eq *func= new Item_func_eq(c, const_item);
-    func->set_cmp_func();
+    if(func->set_cmp_func())
+      return;
     func->quick_fix_field();
     cond_false= !func->val_int();
   }

=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h	2011-11-28 09:36:45 +0000
+++ b/sql/item_cmpfunc.h	2012-01-16 09:01:53 +0000
@@ -370,9 +370,9 @@ public:
   Item_bool_func2(Item *a,Item *b)
     :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {}
   void fix_length_and_dec();
-  void set_cmp_func()
+  int set_cmp_func()
   {
-    cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
+    return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
   }
   optimize_type select_optimize() const { return OPTIMIZE_OP; }
   virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }

=== modified file 'sql/sql_optimizer.cc'
--- a/sql/sql_optimizer.cc	2012-01-09 14:19:49 +0000
+++ b/sql/sql_optimizer.cc	2012-01-16 09:01:53 +0000
@@ -424,6 +424,12 @@ JOIN::optimize()
   if (conds)
   {
     conds= substitute_for_best_equal_field(conds, cond_equal, map2table);
+    if (thd->is_error())
+    {
+      error= 1;
+      DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+      DBUG_RETURN(1);
+    }
     conds->update_used_tables();
     DBUG_EXECUTE("where",
                  print_where(conds,
@@ -442,6 +448,12 @@ JOIN::optimize()
       *tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
                                                          tab->cond_equal,
                                                          map2table);
+      if (thd->is_error())
+      {
+        error= 1;
+        DBUG_PRINT("error",("Error from substitute_for_best_equal"));
+        DBUG_RETURN(1);
+      }
       (*tab->on_expr_ref)->update_used_tables();
     }
   }
@@ -1183,9 +1195,9 @@ static bool check_simple_equality(Item *
         if (!item)
         {
           Item_func_eq *eq_item;
-          if ((eq_item= new Item_func_eq(left_item, right_item)))
+          if (!(eq_item= new Item_func_eq(left_item, right_item)) ||
+              eq_item->set_cmp_func())
             return FALSE;
-          eq_item->set_cmp_func();
           eq_item->quick_fix_field();
           item= eq_item;
         }  
@@ -1276,9 +1288,9 @@ static bool check_row_equality(THD *thd,
     if (!is_converted)
     {
       Item_func_eq *eq_item;
-      if (!(eq_item= new Item_func_eq(left_item, right_item)))
+      if (!(eq_item= new Item_func_eq(left_item, right_item)) ||
+          eq_item->set_cmp_func())
         return FALSE;
-      eq_item->set_cmp_func();
       eq_item->quick_fix_field();
       eq_list->push_back(eq_item);
     }
@@ -1852,10 +1864,8 @@ static Item *eliminate_item_equal(Item *
         head= item_equal->get_first();
 
       eq_item= new Item_func_eq(item_field, head);
-      if (!eq_item)
+      if (!eq_item || eq_item->set_cmp_func())
         return NULL;
-
-      eq_item->set_cmp_func();
       eq_item->quick_fix_field();
     }
   }
@@ -1911,7 +1921,7 @@ static Item *eliminate_item_equal(Item *
     the order in them to comply with the order of upper levels.
 
   @return
-    The transformed condition
+    The transformed condition, or NULL in case of error
 */
 
 static Item* substitute_for_best_equal_field(Item *cond,
@@ -1958,6 +1968,8 @@ static Item* substitute_for_best_equal_f
       while ((item_equal= it++))
       {
         cond= eliminate_item_equal(cond, cond_equal->upper_levels, item_equal);
+        if (cond == NULL)
+          return NULL;
         // This occurs when eliminate_item_equal() founds that cond is
         // always false and substitutes it with Item_int 0.
         // Due to this, value of item_equal will be 0, so just return it.

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (norvald.ryeng:3730 to 3731) Bug#11766143Norvald H. Ryeng16 Jan