diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2013-09-09 15:32:25 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2013-09-09 15:32:25 +0400 |
commit | c2b38529a9ca2ea09dfa73186d9350a0d6dcd6ac (patch) | |
tree | c4aac68dfd58c8f87a6c1cc8d4c456a8fa02e83b /sql/item_cmpfunc.cc | |
parent | 02338228dd48752a48d611b03ce35efd35d143d7 (diff) | |
download | mariadb-git-c2b38529a9ca2ea09dfa73186d9350a0d6dcd6ac.tar.gz |
MDEV-4863 COALESCE(time_or_datetime) returns wrong results in numeric context
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 145 |
1 files changed, 80 insertions, 65 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e133e2811bd..f0069757ee3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2374,12 +2374,13 @@ void Item_func_between::print(String *str, enum_query_type query_type) void Item_func_ifnull::fix_length_and_dec() { - agg_result_type(&hybrid_type, args, 2); + agg_result_type(&cached_result_type, args, 2); + cached_field_type= agg_field_type(args, 2); maybe_null=args[1]->maybe_null; decimals= max(args[0]->decimals, args[1]->decimals); unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag; - if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) + if (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) { int len0= args[0]->max_length - args[0]->decimals - (args[0]->unsigned_flag ? 0 : 1); @@ -2392,9 +2393,10 @@ Item_func_ifnull::fix_length_and_dec() else max_length= max(args[0]->max_length, args[1]->max_length); - switch (hybrid_type) { + switch (cached_result_type) { case STRING_RESULT: - agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1); + if (count_string_result_length(cached_field_type, args, arg_count)) + return; break; case DECIMAL_RESULT: case REAL_RESULT: @@ -2407,7 +2409,6 @@ Item_func_ifnull::fix_length_and_dec() case IMPOSSIBLE_RESULT: DBUG_ASSERT(0); } - cached_field_type= agg_field_type(args, 2); } @@ -2421,11 +2422,6 @@ uint Item_func_ifnull::decimal_precision() const } -enum_field_types Item_func_ifnull::field_type() const -{ - return cached_field_type; -} - Field *Item_func_ifnull::tmp_table_field(TABLE *table) { return tmp_table_field_from_field_type(table, 0); @@ -2499,6 +2495,18 @@ Item_func_ifnull::str_op(String *str) } +bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, uint fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + if (!args[0]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)) + return (null_value= false); + if (!args[1]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES)) + return (null_value= false); + bzero((char*) ltime,sizeof(*ltime)); + return null_value= !(fuzzydate & TIME_FUZZY_DATES); +} + + /** Perform context analysis of an IF item tree. @@ -2587,16 +2595,16 @@ Item_func_if::fix_length_and_dec() else { agg_result_type(&cached_result_type, args+1, 2); + cached_field_type= agg_field_type(args + 1, 2); if (cached_result_type == STRING_RESULT) { - if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV, 1)) - return; + count_string_result_length(cached_field_type, args + 1, 2); + return; } else { collation.set(&my_charset_bin); // Number } - cached_field_type= agg_field_type(args + 1, 2); } if ((cached_result_type == DECIMAL_RESULT ) @@ -2625,7 +2633,7 @@ uint Item_func_if::decimal_precision() const double -Item_func_if::val_real() +Item_func_if::real_op() { DBUG_ASSERT(fixed == 1); Item *arg= args[0]->val_bool() ? args[1] : args[2]; @@ -2635,7 +2643,7 @@ Item_func_if::val_real() } longlong -Item_func_if::val_int() +Item_func_if::int_op() { DBUG_ASSERT(fixed == 1); Item *arg= args[0]->val_bool() ? args[1] : args[2]; @@ -2645,7 +2653,7 @@ Item_func_if::val_int() } String * -Item_func_if::val_str(String *str) +Item_func_if::str_op(String *str) { DBUG_ASSERT(fixed == 1); Item *arg= args[0]->val_bool() ? args[1] : args[2]; @@ -2658,7 +2666,7 @@ Item_func_if::val_str(String *str) my_decimal * -Item_func_if::val_decimal(my_decimal *decimal_value) +Item_func_if::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); Item *arg= args[0]->val_bool() ? args[1] : args[2]; @@ -2668,6 +2676,14 @@ Item_func_if::val_decimal(my_decimal *decimal_value) } +bool Item_func_if::date_op(MYSQL_TIME *ltime, uint fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + Item *arg= args[0]->val_bool() ? args[1] : args[2]; + return (null_value= arg->get_date(ltime, fuzzydate)); +} + + void Item_func_nullif::fix_length_and_dec() { @@ -2826,7 +2842,7 @@ Item *Item_func_case::find_item(String *str) } -String *Item_func_case::val_str(String *str) +String *Item_func_case::str_op(String *str) { DBUG_ASSERT(fixed == 1); String *res; @@ -2844,7 +2860,7 @@ String *Item_func_case::val_str(String *str) } -longlong Item_func_case::val_int() +longlong Item_func_case::int_op() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; @@ -2862,7 +2878,7 @@ longlong Item_func_case::val_int() return res; } -double Item_func_case::val_real() +double Item_func_case::real_op() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; @@ -2881,7 +2897,7 @@ double Item_func_case::val_real() } -my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) +my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; @@ -2901,6 +2917,18 @@ my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) } +bool Item_func_case::date_op(MYSQL_TIME *ltime, uint fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + char buff[MAX_FIELD_WIDTH]; + String dummy_str(buff, sizeof(buff), default_charset()); + Item *item= find_item(&dummy_str); + if (!item) + return (null_value= true); + return (null_value= item->get_date(ltime, fuzzydate)); +} + + bool Item_func_case::fix_fields(THD *thd, Item **ref) { /* @@ -2946,7 +2974,10 @@ void Item_func_case::fix_length_and_dec() uint found_types= 0; if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; - + + if (else_expr_num == -1 || args[else_expr_num]->maybe_null) + maybe_null= 1; + /* Aggregate all THEN and ELSE expression types and collations when string result @@ -2959,13 +2990,29 @@ void Item_func_case::fix_length_and_dec() agg[nagg++]= args[else_expr_num]; agg_result_type(&cached_result_type, agg, nagg); - if ((cached_result_type == STRING_RESULT) && - agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1)) - return; - cached_field_type= agg_field_type(agg, nagg); + + if (cached_result_type == STRING_RESULT) + { + if (count_string_result_length(cached_field_type, agg, nagg)) + return; + } + else + { + max_length= 0; + decimals= 0; + unsigned_flag= TRUE; + for (uint i= 0; i < nagg; i++) + agg_num_lengths(agg[i]); + if (else_expr_num != -1) + agg_num_lengths(args[else_expr_num]); + max_length= my_decimal_precision_to_length(max_length + decimals, decimals, + unsigned_flag); + } + + /* - Aggregate first expression and all THEN expression types + Aggregate first expression and all WHEN expression types and collations when string comparison */ if (first_expr_num != -1) @@ -3019,29 +3066,6 @@ void Item_func_case::fix_length_and_dec() args[i]->cmp_context= item_cmp_type(left_result_type, args[i]->result_type()); } - - if (else_expr_num == -1 || args[else_expr_num]->maybe_null) - maybe_null=1; - - max_length=0; - decimals=0; - unsigned_flag= TRUE; - if (cached_result_type == STRING_RESULT) - { - for (uint i= 0; i < ncases; i+= 2) - agg_str_lengths(args[i + 1]); - if (else_expr_num != -1) - agg_str_lengths(args[else_expr_num]); - } - else - { - for (uint i= 0; i < ncases; i+= 2) - agg_num_lengths(args[i + 1]); - if (else_expr_num != -1) - agg_num_lengths(args[else_expr_num]); - max_length= my_decimal_precision_to_length(max_length + decimals, decimals, - unsigned_flag); - } } @@ -3149,7 +3173,7 @@ double Item_func_coalesce::real_op() } -bool Item_func_coalesce::get_date(MYSQL_TIME *ltime,uint fuzzydate) +bool Item_func_coalesce::date_op(MYSQL_TIME *ltime,uint fuzzydate) { DBUG_ASSERT(fixed == 1); null_value= 0; @@ -3182,20 +3206,11 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) void Item_func_coalesce::fix_length_and_dec() { cached_field_type= agg_field_type(args, arg_count); - agg_result_type(&hybrid_type, args, arg_count); - Item_result cmp_type; - agg_cmp_type(&cmp_type, args, arg_count); - ///< @todo let result_type() return TIME_RESULT and remove this special case - if (cmp_type == TIME_RESULT) - { - count_real_length(); - return; - } - switch (hybrid_type) { + agg_result_type(&cached_result_type, args, arg_count); + switch (cached_result_type) { case STRING_RESULT: - count_only_length(); - decimals= NOT_FIXED_DEC; - agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1); + if (count_string_result_length(cached_field_type, args, arg_count)) + return; break; case DECIMAL_RESULT: count_decimal_length(); @@ -3204,7 +3219,7 @@ void Item_func_coalesce::fix_length_and_dec() count_real_length(); break; case INT_RESULT: - count_only_length(); + count_only_length(args, arg_count); decimals= 0; break; case ROW_RESULT: |