summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2013-09-09 15:32:25 +0400
committerAlexander Barkov <bar@mnogosearch.org>2013-09-09 15:32:25 +0400
commitc2b38529a9ca2ea09dfa73186d9350a0d6dcd6ac (patch)
treec4aac68dfd58c8f87a6c1cc8d4c456a8fa02e83b /sql/item_cmpfunc.cc
parent02338228dd48752a48d611b03ce35efd35d143d7 (diff)
downloadmariadb-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.cc145
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: