List:Commits« Previous MessageNext Message »
From:Evgeny Potemkin Date:November 5 2008 1:09pm
Subject:bzr commit into mysql-5.1 branch (epotemkin:2694) Bug#37870
View as plain text  
#At file:///work/bzr_trees/37870-bug-5.1-bugteam/

 2694 Evgeny Potemkin	2008-11-05
      Bug#37870: Usage of uninitialized value caused failed assertion.
      
      The convert_constant_item function converts a constant to integer using
      field for condition like 'field = a_constant'. In some cases the
      convert_constant_item is called for a subquery when outer select is already
      being executed, so convert_constant_item saves field's value to prevent its
      corruption. For EXPLAIN and at the prepare phase field's value isn't
      initialized yet, thus when convert_constant_item tries to restore saved
      value it fails assertion.
modified:
  mysql-test/r/explain.result
  mysql-test/t/explain.test
  sql/item_cmpfunc.cc
  sql/sql_select.cc
  sql/sql_select.h

per-file messages:
  mysql-test/r/explain.result
    Added a test case for the bug#37870.
  mysql-test/t/explain.test
    Added a test case for the bug#37870.
  sql/item_cmpfunc.cc
    Bug#37870: Usage of uninitialized value caused failed assertion.
    Now the convert_constant_item doesn't save/restore field's value for EXPLAIN
    and at the prepare phase since it's not initialized. Outer constants values
    are always saved.
  sql/sql_select.cc
    Bug#37870: Usage of uninitialized value caused failed assertion.
    JOIN::exec now sets JOIN::executing flag.
  sql/sql_select.h
    Bug#37870: Usage of uninitialized value caused failed assertion.
    Added flag called executing to the JOIN class. It's used to indicate that the
    JOIN is being executed.
=== modified file 'mysql-test/r/explain.result'
--- a/mysql-test/r/explain.result	2008-10-27 12:04:51 +0000
+++ b/mysql-test/r/explain.result	2008-11-05 13:09:48 +0000
@@ -158,15 +158,27 @@ DROP TABLE t1,t2;
 #
 # Bug#37870: Usage of uninitialized value caused failed assertion.
 #
-create table t1 (dt datetime not null);
+create table t1 (dt datetime not null, t time not null);
 create table t2 (dt datetime not null);
-insert into t1 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1');
+insert into t1 values ('2001-01-01 1:1:1', '1:1:1'),
+('2001-01-01 1:1:1', '1:1:1');
 insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1');
 flush tables;
 EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL );
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	OUTR	ALL	NULL	NULL	NULL	NULL	2	Using where
 2	DEPENDENT SUBQUERY	INNR	ALL	NULL	NULL	NULL	NULL	2	Using where
+flush tables;
 SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL );
 dt
+flush tables;
+EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	OUTR	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	INNR	ALL	NULL	NULL	NULL	NULL	2	Using where
+flush tables;
+SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' );
+dt
+2001-01-01 01:01:01
+2001-01-01 01:01:01
 drop tables t1, t2;

=== modified file 'mysql-test/t/explain.test'
--- a/mysql-test/t/explain.test	2008-10-27 12:04:51 +0000
+++ b/mysql-test/t/explain.test	2008-11-05 13:09:48 +0000
@@ -126,13 +126,19 @@ DROP TABLE t1,t2;
 --echo #
 --echo # Bug#37870: Usage of uninitialized value caused failed assertion.
 --echo #
-create table t1 (dt datetime not null);
+create table t1 (dt datetime not null, t time not null);
 create table t2 (dt datetime not null);
-insert into t1 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1');
+insert into t1 values ('2001-01-01 1:1:1', '1:1:1'),
+('2001-01-01 1:1:1', '1:1:1');
 insert into t2 values ('2001-01-01 1:1:1'), ('2001-01-01 1:1:1');
 flush tables;
 EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL );
+flush tables;
 SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN (SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.dt IS NULL );
+flush tables;
+EXPLAIN SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); 
+flush tables;
+SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' );
 drop tables t1, t2;
 
 # End of 5.0 tests.

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2008-10-27 16:19:26 +0000
+++ b/sql/item_cmpfunc.cc	2008-11-05 13:09:48 +0000
@@ -415,9 +415,13 @@ static bool convert_constant_item(THD *t
     /*
       Store the value of the field/constant if it references an outer field because
       the call to save_in_field below overrides that value.
-      Don't save value of the field for EXPLAIN since it's not initialized.
+      Don't save field value of the field for EXPLAIN and at the prepare phase
+      since it's not initialized. Outer constants values are always saved.
     */
-    if (field_item->depended_from && (!thd->lex->describe || field_item->const_item()))
+    if (field_item->depended_from &&
+        ((!thd->lex->describe &&
+          field_item->depended_from->join->executing) ||
+         field_item->const_item()))
       orig_field_val= field->val_int();
     if (!(*item)->is_null() && !(*item)->save_in_field(field, 1))
     {
@@ -428,7 +432,10 @@ static bool convert_constant_item(THD *t
       result= 1;					// Item was replaced
     }
     /* Restore the original field value. */
-    if (field_item->depended_from && (!thd->lex->describe || field_item->const_item()))
+    if (field_item->depended_from &&
+        ((!thd->lex->describe &&
+          field_item->depended_from->join->executing) ||
+         field_item->const_item()))
     {
       result= field->store(orig_field_val, TRUE);
       /* orig_field_val must be a valid value that can be restored back. */

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-11-03 10:40:58 +0000
+++ b/sql/sql_select.cc	2008-11-05 13:09:48 +0000
@@ -1690,6 +1690,7 @@ JOIN::exec()
     thd->examined_row_count= 0;
     DBUG_VOID_RETURN;
   }
+  executing= TRUE;
   /*
     Don't reset the found rows count if there're no tables as
     FOUND_ROWS() may be called. Never reset the examined row count here.

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2008-10-24 12:50:59 +0000
+++ b/sql/sql_select.h	2008-11-05 13:09:48 +0000
@@ -391,7 +391,7 @@ public:
   
   bool union_part; ///< this subselect is part of union 
   bool optimized; ///< flag to avoid double optimization in EXPLAIN
-
+  bool executing; ///< JOIN execution is in progress (JOIN::exec is called)
   /* 
     storage for caching buffers allocated during query execution. 
     These buffers allocations need to be cached as the thread memory pool is
@@ -455,6 +455,7 @@ public:
     ref_pointer_array_size= 0;
     zero_result_cause= 0;
     optimized= 0;
+    executing= 0;
     cond_equal= 0;
     group_optimized_away= 0;
 

Thread
bzr commit into mysql-5.1 branch (epotemkin:2694) Bug#37870Evgeny Potemkin5 Nov