diff options
author | Sergey Petrunya <psergey@askmonty.org> | 2013-08-23 16:32:56 +0400 |
---|---|---|
committer | Sergey Petrunya <psergey@askmonty.org> | 2013-08-23 16:32:56 +0400 |
commit | 970542ec90951c3e9d68ff310cdf181465854aaa (patch) | |
tree | 8cad06c470ae4b87ffe339ca58f4f7e28a7714a9 /sql | |
parent | f5ea23b6e2bedb4bdaed7f53325cfce35acc8a3e (diff) | |
download | mariadb-git-970542ec90951c3e9d68ff310cdf181465854aaa.tar.gz |
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".
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_cmpfunc.cc | 27 | ||||
-rw-r--r-- | sql/sql_select.cc | 76 | ||||
-rw-r--r-- | sql/sql_select.h | 1 |
3 files changed, 87 insertions, 17 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6f975541c55..15692b454fe 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4302,7 +4302,8 @@ Item_cond::fix_fields(THD *thd, Item **ref) 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 **ref) /* 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 *opt_arg) 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 ..." diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bdede4e831b..ba72b03c828 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13523,6 +13523,35 @@ void propagate_new_equalities(THD *thd, Item *cond, } +/* + 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 *cond, Item::cond_result *cond_value) return item; } } + else if (cond_is_datetime_is_null(cond)) + { + /* fix to replace 'NULL' dates with '0' (shreeve@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 *cond, Item::cond_result *cond_value) return (COND*) 0; } } +#endif else if (cond->const_item() && !cond->is_expensive()) { *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE; diff --git a/sql/sql_select.h b/sql/sql_select.h index 478eede7108..fd12cfae335 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1795,6 +1795,7 @@ ORDER *simple_remove_const(ORDER *order, COND *where); 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); |