diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7ecffc20e9f..a015b97f846 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -301,6 +301,26 @@ bool Item_func_nop_all::val_bool() 1 Item was replaced with an integer version of the item */ +/* + Check if constants compared to field_item can be replaced by + integer constants, see convert_const_to_int(). +*/ +static bool is_int_field_for_const_conversion(const Item_field *field_item) +{ + switch (field_item->field_type()) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_YEAR: + return true; + default: + return false; + } +} + + static bool convert_const_to_int(THD *thd, Item_field *field_item, Item **item) { @@ -319,6 +339,18 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item, field_item->field_type() != MYSQL_TYPE_YEAR) return 1; + /* + For BIGINT and YEAR the conversion is done for any constant. + For the other integer types it is done only if it is exact and + does not produce any warnings: otherwise the original comparison, + e.g. as DOUBLE or DATETIME, and its warnings (errors in strict mode) + are kept. + */ + const bool strict= field_item->field_type() != MYSQL_TYPE_LONGLONG && + field_item->field_type() != MYSQL_TYPE_YEAR; + if (strict && (*item)->cmp_type() == TIME_RESULT) + return 0; + /* Replace (*item) with its value if the item can be computed. @@ -352,16 +384,30 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item, !(field->table->status & STATUS_NO_RECORD)); if (save_field_value) orig_field_val= field->val_int(); - if (!(*item)->save_in_field(field, 1) && !field->is_null()) + Dummy_error_handler warnings; + if (strict) + thd->push_internal_handler(&warnings); + bool stored= !(*item)->save_in_field(field, 1) && !field->is_null(); + int field_cmp= 0; + /* + Reject the conversion if the value was truncated or rounded, + e.g. int_column='46.5' or tinyint_column='300'. + YEAR is not checked: YEAR comparison relies on the conversion, + e.g. year_column=1999.1 matches 1999. + */ + if (stored && field->type() != MYSQL_TYPE_YEAR) + { + field_cmp= stored_field_cmp_to_item(thd, field, *item); + DBUG_PRINT("info", ("convert_const_to_int %d", field_cmp)); + } + if (strict) + { + thd->pop_internal_handler(); + if (warnings.any_error()) + stored= false; + } + if (stored) { - int field_cmp= 0; - // If item is a decimal value, we must reject it if it was truncated. - if (field->type() == MYSQL_TYPE_LONGLONG) - { - field_cmp= stored_field_cmp_to_item(thd, field, *item); - DBUG_PRINT("info", ("convert_const_to_int %d", field_cmp)); - } - if (0 == field_cmp) { Item *tmp= (new (thd->mem_root) @@ -403,9 +449,8 @@ void Item_func::convert_const_compared_to_int_field(THD *thd) args[field= 1]->real_item()->type() == FIELD_ITEM) { Item_field *field_item= (Item_field*) (args[field]->real_item()); - if (((field_item->field_type() == MYSQL_TYPE_LONGLONG && - field_item->type_handler() != &type_handler_vers_trx_id) || - field_item->field_type() == MYSQL_TYPE_YEAR)) + if (is_int_field_for_const_conversion(field_item) && + field_item->type_handler() != &type_handler_vers_trx_id) convert_const_to_int(thd, field_item, &args[!field]); } } @@ -2216,8 +2261,7 @@ bool Item_func_between::fix_length_and_dec_numeric(THD *thd) !thd->lex->is_ps_or_view_context_analysis()) { Item_field *field_item= (Item_field*) (args[0]->real_item()); - if (field_item->field_type() == MYSQL_TYPE_LONGLONG || - field_item->field_type() == MYSQL_TYPE_YEAR) + if (is_int_field_for_const_conversion(field_item)) { const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]); const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]); @@ -4672,8 +4716,7 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd) !thd->lex->is_view_context_analysis()) { Item_field *field_item= (Item_field*) (args[0]->real_item()); - if (field_item->field_type() == MYSQL_TYPE_LONGLONG || - field_item->field_type() == MYSQL_TYPE_YEAR) + if (is_int_field_for_const_conversion(field_item)) { bool all_converted= true; Item **arg, **arg_end;