List:Commits« Previous MessageNext Message »
From:timour Date:December 8 2007 10:05pm
Subject:bk commit into 5.0 tree (timour:1.2597) BUG#32694
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 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-12-08 23:05:00+02:00, timour@stripped +3 -0
  Fix for BUG#32694 "NOT NULL table field in a subquery produces invalid results"
    
  The problem was that when convert_constant_item is called for subqueries,
  this happens when we already started executing the top-level query, and
  the field argument of convert_constant_item pointed to a valid table row.
  In turn convert_constant_item used the field buffer to compute the value
  of its item argument. This copied the item's value into the field,
  and made equalities with outer references always true.
    
  The fix saves/restores the original field's value when it belongs to an
  outer table.

  mysql-test/r/type_datetime.result@stripped, 2007-12-08 23:04:56+02:00, timour@stripped
+55 -0
    Test for BUG#32694.

  mysql-test/t/type_datetime.test@stripped, 2007-12-08 23:04:58+02:00, timour@stripped
+37 -0
    Test for BUG#32694.

  sql/item_cmpfunc.cc@stripped, 2007-12-08 23:04:58+02:00, timour@stripped +41 -26
    - Changed convert_constant_item() so that it doesn't destroy the contents
      of its field argument when the field originates from table in an outer
      query.

diff -Nrup a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
--- a/mysql-test/r/type_datetime.result	2007-10-29 12:58:08 +02:00
+++ b/mysql-test/r/type_datetime.result	2007-12-08 23:04:56 +02:00
@@ -505,4 +505,59 @@ select sum(a) from t1 group by convert(a
 sum(a)
 NULL
 drop table t1;
+create table t1 (id int(10) not null, cur_date datetime not null);
+create table t2 (id int(10) not null, cur_date date not null);
+insert into t1 (id, cur_date) values (1, '2007-04-25 18:30:22');
+insert into t2 (id, cur_date) values (1, '2007-04-25');
+explain extended
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const
tables
+2	DEPENDENT SUBQUERY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE
+Warnings:
+Note	1276	Field or reference 'test.t1.cur_date' of SELECT #2 was resolved in SELECT #1
+Note	1003	select '1' AS `id`,'2007-04-25 18:30:22' AS `cur_date` from `test`.`t1` where
<in_optimizer>('1',<exists>(select 1 AS `Not_used` from `test`.`t1` `x1`
where 0))
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+id	cur_date
+explain extended
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const
tables
+2	DEPENDENT SUBQUERY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE
+Warnings:
+Note	1276	Field or reference 'test.t2.cur_date' of SELECT #2 was resolved in SELECT #1
+Note	1003	select '1' AS `id`,'2007-04-25' AS `cur_date` from `test`.`t2` where
<in_optimizer>('1',<exists>(select 1 AS `Not_used` from `test`.`t2` `x1`
where 0))
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+id	cur_date
+insert into t1 (id, cur_date) values (2, '2007-04-26 18:30:22');
+insert into t2 (id, cur_date) values (2, '2007-04-26');
+explain extended
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	x1	ALL	NULL	NULL	NULL	NULL	2	Using where
+Warnings:
+Note	1276	Field or reference 'test.t1.cur_date' of SELECT #2 was resolved in SELECT #1
+Note	1003	select `test`.`t1`.`id` AS `id`,`test`.`t1`.`cur_date` AS `cur_date` from
`test`.`t1` where <in_optimizer>(`test`.`t1`.`id`,<exists>(select 1 AS
`Not_used` from `test`.`t1` `x1` where ((`test`.`t1`.`cur_date` = 0) and
(<cache>(`test`.`t1`.`id`) = `test`.`x1`.`id`))))
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+id	cur_date
+explain extended
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	x1	ALL	NULL	NULL	NULL	NULL	2	Using where
+Warnings:
+Note	1276	Field or reference 'test.t2.cur_date' of SELECT #2 was resolved in SELECT #1
+Note	1003	select `test`.`t2`.`id` AS `id`,`test`.`t2`.`cur_date` AS `cur_date` from
`test`.`t2` where <in_optimizer>(`test`.`t2`.`id`,<exists>(select 1 AS
`Not_used` from `test`.`t2` `x1` where ((`test`.`t2`.`cur_date` = 0) and
(<cache>(`test`.`t2`.`id`) = `test`.`x1`.`id`))))
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+id	cur_date
+drop table t1,t2;
 End of 5.0 tests
diff -Nrup a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
--- a/mysql-test/t/type_datetime.test	2007-10-23 16:51:41 +03:00
+++ b/mysql-test/t/type_datetime.test	2007-12-08 23:04:58 +02:00
@@ -338,4 +338,41 @@ insert into t1 values (), (), ();
 select sum(a) from t1 group by convert(a, datetime);
 drop table t1;
 
+#
+# Bug #32694: NOT NULL table field in a subquery produces invalid results
+#
+create table t1 (id int(10) not null, cur_date datetime not null);
+create table t2 (id int(10) not null, cur_date date not null);
+insert into t1 (id, cur_date) values (1, '2007-04-25 18:30:22');
+insert into t2 (id, cur_date) values (1, '2007-04-25');
+
+explain extended
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+
+explain extended
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+
+insert into t1 (id, cur_date) values (2, '2007-04-26 18:30:22');
+insert into t2 (id, cur_date) values (2, '2007-04-26');
+
+explain extended
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+select * from t1
+where id in (select id from t1 as x1 where (t1.cur_date is null));
+
+explain extended
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+select * from t2
+where id in (select id from t2 as x1 where (t2.cur_date is null));
+
+drop table t1,t2;
+
 --echo End of 5.0 tests
diff -Nrup a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
--- a/sql/item_cmpfunc.cc	2007-11-17 22:01:29 +02:00
+++ b/sql/item_cmpfunc.cc	2007-12-08 23:04:58 +02:00
@@ -24,7 +24,8 @@
 #include <m_ctype.h>
 #include "sql_select.h"
 
-static bool convert_constant_item(THD *thd, Field *field, Item **item);
+static bool convert_constant_item(THD *thd, Item_field *field_item,
+                                  Item **item);
 
 static Item_result item_store_type(Item_result a, Item *item,
                                    my_bool unsigned_flag)
@@ -317,7 +318,7 @@ longlong Item_func_nop_all::val_int()
   SYNOPSIS
     convert_constant_item()
     thd             thread handle
-    field           item will be converted using the type of this field
+    field_item      item will be converted using the type of this field
     item  [in/out]  reference to the item to convert
 
   DESCRIPTION
@@ -340,30 +341,46 @@ longlong Item_func_nop_all::val_int()
   1	Item was replaced with an integer version of the item
 */
 
-static bool convert_constant_item(THD *thd, Field *field, Item **item)
+static bool convert_constant_item(THD *thd, Item_field *field_item,
+                                  Item **item)
 {
+  Field *field= field_item->field;
+  int result= 0;
+
   if (!(*item)->with_subselect && (*item)->const_item())
   {
     /* For comparison purposes allow invalid dates like 2000-01-32 */
     ulong orig_sql_mode= thd->variables.sql_mode;
     enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
+    ulonglong orig_field_val; /* original field value if valid */
     thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) | 
                              MODE_INVALID_DATES;
     thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+    /*
+      Store the value of the field if it references an outer field because
+      the call to save_in_field below overrides that value.
+    */
+    if (field_item->depended_from)
+      orig_field_val= field->val_int();
     if (!(*item)->is_null() && !(*item)->save_in_field(field, 1))
     {
       Item *tmp=new Item_int_with_ref(field->val_int(), *item,
                                       test(field->flags & UNSIGNED_FLAG));
-      thd->variables.sql_mode= orig_sql_mode;
-      thd->count_cuted_fields= orig_count_cuted_fields;
       if (tmp)
         thd->change_item_tree(item, tmp);
-      return 1;					// Item was replaced
+      result= 1;					// Item was replaced
+    }
+    /* Restore the original field value. */
+    if (field_item->depended_from)
+    {
+      result= field->store(orig_field_val, TRUE);
+      /* orig_field_val must be a valid value that can be restored back. */
+      DBUG_ASSERT(!result);
     }
     thd->variables.sql_mode= orig_sql_mode;
     thd->count_cuted_fields= orig_count_cuted_fields;
   }
-  return 0;
+  return result;
 }
 
 
@@ -411,15 +428,14 @@ void Item_bool_func2::fix_length_and_dec
   thd= current_thd;
   if (!thd->is_context_analysis_only())
   {
-    Item *arg_real_item= args[0]->real_item();
-    if (arg_real_item->type() == FIELD_ITEM)
+    if (args[0]->real_item()->type() == FIELD_ITEM)
     {
-      Field *field=((Item_field*) arg_real_item)->field;
-      if (field->can_be_compared_as_longlong() &&
-          !(arg_real_item->is_datetime() &&
+      Item_field *field_item= (Item_field*) (args[0]->real_item());
+      if (field_item->field->can_be_compared_as_longlong() &&
+          !(field_item->is_datetime() &&
             args[1]->result_type() == STRING_RESULT))
       {
-        if (convert_constant_item(thd, field,&args[1]))
+        if (convert_constant_item(thd, field_item, &args[1]))
         {
           cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
                            INT_RESULT);		// Works for all types.
@@ -428,15 +444,14 @@ void Item_bool_func2::fix_length_and_dec
         }
       }
     }
-    arg_real_item= args[1]->real_item();
-    if (arg_real_item->type() == FIELD_ITEM)
+    if (args[1]->real_item()->type() == FIELD_ITEM)
     {
-      Field *field=((Item_field*) arg_real_item)->field;
-      if (field->can_be_compared_as_longlong() &&
-          !(arg_real_item->is_datetime() &&
+      Item_field *field_item= (Item_field*) (args[1]->real_item());
+      if (field_item->field->can_be_compared_as_longlong() &&
+          !(field_item->is_datetime() &&
             args[0]->result_type() == STRING_RESULT))
       {
-        if (convert_constant_item(thd, field,&args[0]))
+        if (convert_constant_item(thd, field_item, &args[0]))
         {
           cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
                            INT_RESULT); // Works for all types.
@@ -1889,16 +1904,16 @@ void Item_func_between::fix_length_and_d
            thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
            thd->lex->sql_command != SQLCOM_SHOW_CREATE)
   {
-    Field *field=((Item_field*) (args[0]->real_item()))->field;
-    if (field->can_be_compared_as_longlong())
+    Item_field *field_item= (Item_field*) (args[0]->real_item());
+    if (field_item->field->can_be_compared_as_longlong())
     {
       /*
         The following can't be recoded with || as convert_constant_item
         changes the argument
       */
-      if (convert_constant_item(thd, field,&args[1]))
+      if (convert_constant_item(thd, field_item, &args[1]))
         cmp_type=INT_RESULT;			// Works for all types.
-      if (convert_constant_item(thd, field,&args[2]))
+      if (convert_constant_item(thd, field_item, &args[2]))
         cmp_type=INT_RESULT;			// Works for all types.
     }
   }
@@ -3491,13 +3506,13 @@ void Item_func_in::fix_length_and_dec()
           thd->lex->sql_command != SQLCOM_SHOW_CREATE &&
           cmp_type != INT_RESULT)
       {
-        Field *field= ((Item_field*) (args[0]->real_item()))->field;
-        if (field->can_be_compared_as_longlong())
+        Item_field *field_item= (Item_field*) (args[0]->real_item());
+        if (field_item->field->can_be_compared_as_longlong())
         {
           bool all_converted= TRUE;
           for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
           {
-            if (!convert_constant_item (thd, field, &arg[0]))
+            if (!convert_constant_item (thd, field_item, &arg[0]))
               all_converted= FALSE;
           }
           if (all_converted)
Thread
bk commit into 5.0 tree (timour:1.2597) BUG#32694timour8 Dec