[Commits] Rev 3859: MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working) in file:///data0/psergey/dev2/5.5/

Sergey Petrunya psergey at askmonty.org
Fri Aug 23 15:32:57 EEST 2013


At file:///data0/psergey/dev2/5.5/

------------------------------------------------------------
revno: 3859
revision-id: psergey at askmonty.org-20130823123256-c4zh1ovpmuz1bgin
parent: psergey at askmonty.org-20130822101346-sc32vyfgsgygh3x5
committer: Sergey Petrunya <psergey at askmonty.org>
branch nick: 5.5
timestamp: Fri 2013-08-23 16:32:56 +0400
message:
  MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
  - When applying optimization introduced by MDEV-4817, ignore the conditions that have form
    "datetime_not_null_col IS NULL".
=== modified file 'mysql-test/r/join_outer.result'
--- a/mysql-test/r/join_outer.result	2013-08-19 02:58:51 +0000
+++ b/mysql-test/r/join_outer.result	2013-08-23 12:32:56 +0000
@@ -2138,4 +2138,16 @@ id	select_type	table	type	possible_keys
 1	SIMPLE	t0	ALL	NULL	NULL	NULL	NULL	10	Using where
 1	SIMPLE	t1	eq_ref	PRIMARY	PRIMARY	4	test.t0.a	1	Using index
 drop table t0, t1;
+#
+# MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
+#  (this is a regression after fix for MDEV-4817)
+#
+CREATE TABLE t1 (id INT, d DATE NOT NULL);
+INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
+CREATE TABLE t2 (i INT);
+SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
+id	d	i
+1	0000-00-00	NULL
+2	0000-00-00	NULL
+DROP TABLE t1,t2;
 SET optimizer_switch=@save_optimizer_switch;

=== modified file 'mysql-test/r/join_outer_jcl6.result'
--- a/mysql-test/r/join_outer_jcl6.result	2013-08-19 02:58:51 +0000
+++ b/mysql-test/r/join_outer_jcl6.result	2013-08-23 12:32:56 +0000
@@ -2149,6 +2149,18 @@ id	select_type	table	type	possible_keys
 1	SIMPLE	t0	ALL	NULL	NULL	NULL	NULL	10	Using where
 1	SIMPLE	t1	eq_ref	PRIMARY	PRIMARY	4	test.t0.a	1	Using index
 drop table t0, t1;
+#
+# MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
+#  (this is a regression after fix for MDEV-4817)
+#
+CREATE TABLE t1 (id INT, d DATE NOT NULL);
+INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
+CREATE TABLE t2 (i INT);
+SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
+id	d	i
+1	0000-00-00	NULL
+2	0000-00-00	NULL
+DROP TABLE t1,t2;
 SET optimizer_switch=@save_optimizer_switch;
 set join_cache_level=default;
 show variables like 'join_cache_level';

=== modified file 'mysql-test/t/join_outer.test'
--- a/mysql-test/t/join_outer.test	2013-07-31 13:24:52 +0000
+++ b/mysql-test/t/join_outer.test	2013-08-23 12:32:56 +0000
@@ -1686,5 +1686,14 @@ explain select * from t1 left join t0 on
 
 drop table t0, t1;
 
+--echo #
+--echo # MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
+--echo #  (this is a regression after fix for MDEV-4817)
+--echo #
+CREATE TABLE t1 (id INT, d DATE NOT NULL);
+INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
+CREATE TABLE t2 (i INT);
+SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
+DROP TABLE t1,t2;
 
 SET optimizer_switch=@save_optimizer_switch;

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2013-08-21 18:27:02 +0000
+++ b/sql/item_cmpfunc.cc	2013-08-23 12:32:56 +0000
@@ -4302,7 +4302,8 @@ Item_cond::fix_fields(THD *thd, Item **r
     used_tables_cache|=     item->used_tables();
     if (item->const_item())
     {
-      if (!item->is_expensive() && item->val_int() == 0)
+      if (!item->is_expensive() && !cond_is_datetime_is_null(item) && 
+          item->val_int() == 0)
       {
         /* 
           This is "... OR false_cond OR ..." 
@@ -4314,27 +4315,18 @@ Item_cond::fix_fields(THD *thd, Item **r
         /* 
           This is  "... OR const_cond OR ..."
           In this case, cond_or->not_null_tables()=0, because the condition
-          some_cond_or might be true regardless of what tables are 
-          NULL-complemented.
+          const_cond might evaluate to true (regardless of whether some tables
+          were NULL-complemented).
         */
         and_tables_cache= (table_map) 0;
       }
     }
     else
     {
-      /*
-        If an item is a 
-         - constant
-         - inexpensive 
-         - its value is 0
-        then we don't need to account it in not_null_tables_cache
-      */
-      //if (!(item->const_item() && !item->is_expensive() ))
-      {
-        table_map tmp_table_map= item->not_null_tables();
-        not_null_tables_cache|= tmp_table_map;
-        and_tables_cache&= tmp_table_map;
-      }
+      table_map tmp_table_map= item->not_null_tables();
+      not_null_tables_cache|= tmp_table_map;
+      and_tables_cache&= tmp_table_map;
+
       const_item_cache= FALSE;
     } 
   
@@ -4363,7 +4355,8 @@ Item_cond::eval_not_null_tables(uchar *o
     table_map tmp_table_map;
     if (item->const_item())
     {
-      if (!item->is_expensive() && item->val_int() == 0)
+      if (!item->is_expensive() && !cond_is_datetime_is_null(item) && 
+          item->val_int() == 0)
       {
         /* 
           This is "... OR false_cond OR ..." 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2013-08-21 18:27:02 +0000
+++ b/sql/sql_select.cc	2013-08-23 12:32:56 +0000
@@ -13523,6 +13523,35 @@ void propagate_new_equalities(THD *thd,
 } 
 
 
+/*
+  Check if passed condtition has for of
+
+    not_null_date_col IS NULL
+
+  where not_null_date_col has a datte or datetime type
+*/
+
+bool cond_is_datetime_is_null(Item *cond)
+{
+  if (cond->type() == Item::FUNC_ITEM &&
+      ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
+  {
+    Item **args= ((Item_func_isnull*) cond)->arguments();
+    if (args[0]->type() == Item::FIELD_ITEM)
+    {
+      Field *field=((Item_field*) args[0])->field;
+
+      if (((field->type() == MYSQL_TYPE_DATE) ||
+           (field->type() == MYSQL_TYPE_DATETIME)) &&
+          (field->flags & NOT_NULL_FLAG))
+      {
+        return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
+
 
 /**
   @brief
@@ -13776,6 +13805,52 @@ internal_remove_eq_conds(THD *thd, COND
       return item;
     }
   }
+  else if (cond_is_datetime_is_null(cond))
+  {
+    /* fix to replace 'NULL' dates with '0' (shreeve at uci.edu) */
+    /*
+      See BUG#12594011
+      Documentation says that
+      SELECT datetime_notnull d FROM t1 WHERE d IS NULL
+      shall return rows where d=='0000-00-00'
+
+      Thus, for DATE and DATETIME columns defined as NOT NULL,
+      "date_notnull IS NULL" has to be modified to
+      "date_notnull IS NULL OR date_notnull == 0" (if outer join)
+      "date_notnull == 0"                         (otherwise)
+
+    */
+    Item **args= ((Item_func_isnull*) cond)->arguments();
+    Field *field=((Item_field*) args[0])->field;
+
+    Item *item0= new(thd->mem_root) Item_int((longlong)0, 1);
+    Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0);
+    if (!eq_cond)
+      return cond;
+
+    if (field->table->pos_in_table_list->outer_join)
+    {
+      // outer join: transform "col IS NULL" to "col IS NULL or col=0"
+      Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond);
+      if (!or_cond)
+        return cond;
+      cond= or_cond;
+    }
+    else
+    {
+      // not outer join: transform "col IS NULL" to "col=0"
+      cond= eq_cond;
+    }
+
+    cond->fix_fields(thd, &cond);
+
+    if (cond->const_item() && !cond->is_expensive())
+    {
+      *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
+      return (COND*) 0;
+    }
+  }
+#if 0  
   else if (cond->type() == Item::FUNC_ITEM &&
 	   ((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
   {
@@ -13829,6 +13904,7 @@ internal_remove_eq_conds(THD *thd, COND
       return (COND*) 0;
     }
   }
+#endif  
   else if (cond->const_item() && !cond->is_expensive())
   {
     *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2013-07-16 17:09:54 +0000
+++ b/sql/sql_select.h	2013-08-23 12:32:56 +0000
@@ -1795,6 +1795,7 @@ ORDER *simple_remove_const(ORDER *order,
 bool const_expression_in_where(COND *cond, Item *comp_item,
                                Field *comp_field= NULL,
                                Item **const_item= NULL);
+bool cond_is_datetime_is_null(Item *cond);
 
 /* Table elimination entry point function */
 void eliminate_tables(JOIN *join);



More information about the commits mailing list