diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index e2350a13e46..e1be32aa7eb 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -328,8 +328,8 @@ least(cast('01-01-01' as datetime), '01-01-02') + 0 select cast(least(cast('01-01-01' as datetime), '01-01-02') as signed); cast(least(cast('01-01-01' as datetime), '01-01-02') as signed) 20010101000000 -select cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal); -cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal) +select cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal(16,2)); +cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal(16,2)) 20010101000000.00 DROP PROCEDURE IF EXISTS test27759 ; CREATE PROCEDURE test27759() diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index f434d5b77e4..7689f16baa4 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -207,7 +207,7 @@ select least(cast('01-01-01' as date), '01-01-02') + 0; select greatest(cast('01-01-01' as date), '01-01-02') + 0; select least(cast('01-01-01' as datetime), '01-01-02') + 0; select cast(least(cast('01-01-01' as datetime), '01-01-02') as signed); -select cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal); +select cast(least(cast('01-01-01' as datetime), '01-01-02') as decimal(16,2)); --disable_warnings DROP PROCEDURE IF EXISTS test27759 ; --enable_warnings diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 010380dc62d..2e6081ba5f8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3238,7 +3238,13 @@ void Item_func_in::fix_length_and_dec() /* TRUE <=> arguments values will be compared as DATETIMEs. */ bool compare_as_datetime= FALSE; Item *date_arg= 0; - + uint found_types= 0; + uint type_cnt= 0, i; + Item_result cmp_type= STRING_RESULT; + left_result_type= args[0]->result_type(); + if (!(found_types= collect_cmp_types(args, arg_count))) + return; + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) { if (!arg[0]->const_item()) @@ -3247,87 +3253,6 @@ void Item_func_in::fix_length_and_dec() break; } } - /* - When comparing rows create the row comparator object beforehand to ease - the DATETIME comparison detection procedure. - */ - if (cmp_type == ROW_RESULT) - { - cmp_item_row *cmp= 0; - if (const_itm && !nulls_in_row()) - { - array= new in_row(arg_count-1, 0); - cmp= &((in_row*)array)->tmp; - } - else - { - if (!(cmp= new cmp_item_row)) - return; - in_item= cmp; - } - cmp->n= args[0]->cols(); - cmp->alloc_comparators(); - } - /* All DATE/DATETIME fields/functions has the STRING result type. */ - if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT) - { - uint col, cols= args[0]->cols(); - - for (col= 0; col < cols; col++) - { - bool skip_column= FALSE; - /* - Check that all items to be compared has the STRING result type and at - least one of them is a DATE/DATETIME item. - */ - for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++) - { - Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] : - arg[0]->element_index(col)); - if (itm->result_type() != STRING_RESULT) - { - skip_column= TRUE; - break; - } - else if (itm->is_datetime()) - { - datetime_found= TRUE; - /* - Internally all DATE/DATETIME values are converted to the DATETIME - type. So try to find a DATETIME item to issue correct warnings. - */ - if (!date_arg) - date_arg= itm; - else if (itm->field_type() == MYSQL_TYPE_DATETIME) - { - date_arg= itm; - /* All arguments are already checked to have the STRING result. */ - if (cmp_type == STRING_RESULT) - break; - } - } - } - if (skip_column) - continue; - if (datetime_found) - { - if (cmp_type == ROW_RESULT) - { - cmp_item **cmp= 0; - if (array) - cmp= ((in_row*)array)->tmp.comparators + col; - else - cmp= ((cmp_item_row*)in_item)->comparators + col; - *cmp= new cmp_item_datetime(date_arg); - /* Reset variables for the next column. */ - date_arg= 0; - datetime_found= FALSE; - } - else - compare_as_datetime= TRUE; - } - } - } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & 1 << i) @@ -3344,7 +3269,90 @@ void Item_func_in::fix_length_and_dec() return; arg_types_compatible= TRUE; } + if (type_cnt == 1) + { + /* + When comparing rows create the row comparator object beforehand to ease + the DATETIME comparison detection procedure. + */ + if (cmp_type == ROW_RESULT) + { + cmp_item_row *cmp= 0; + if (const_itm && !nulls_in_row()) + { + array= new in_row(arg_count-1, 0); + cmp= &((in_row*)array)->tmp; + } + else + { + if (!(cmp= new cmp_item_row)) + return; + cmp_items[ROW_RESULT]= cmp; + } + cmp->n= args[0]->cols(); + cmp->alloc_comparators(); + } + /* All DATE/DATETIME fields/functions has the STRING result type. */ + if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT) + { + uint col, cols= args[0]->cols(); + for (col= 0; col < cols; col++) + { + bool skip_column= FALSE; + /* + Check that all items to be compared has the STRING result type and at + least one of them is a DATE/DATETIME item. + */ + for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++) + { + Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] : + arg[0]->element_index(col)); + if (itm->result_type() != STRING_RESULT) + { + skip_column= TRUE; + break; + } + else if (itm->is_datetime()) + { + datetime_found= TRUE; + /* + Internally all DATE/DATETIME values are converted to the DATETIME + type. So try to find a DATETIME item to issue correct warnings. + */ + if (!date_arg) + date_arg= itm; + else if (itm->field_type() == MYSQL_TYPE_DATETIME) + { + date_arg= itm; + /* All arguments are already checked to have the STRING result. */ + if (cmp_type == STRING_RESULT) + break; + } + } + } + if (skip_column) + continue; + if (datetime_found) + { + if (cmp_type == ROW_RESULT) + { + cmp_item **cmp= 0; + if (array) + cmp= ((in_row*)array)->tmp.comparators + col; + else + cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col; + *cmp= new cmp_item_datetime(date_arg); + /* Reset variables for the next column. */ + date_arg= 0; + datetime_found= FALSE; + } + else + compare_as_datetime= TRUE; + } + } + } + } /* Row item with NULLs inside can return NULL or FALSE => they can't be processed as static @@ -3424,33 +3432,25 @@ void Item_func_in::fix_length_and_dec() } else { - if (in_item) - { - /* - The row comparator was created at the beginning but only DATETIME - items comparators were initialized. Call store_value() to setup - others. - */ - in_item->store_value(args[0]); - } - else if (compare_as_datetime) - in_item= new cmp_item_datetime(date_arg); + if (compare_as_datetime) + cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg); else { - for (i= 0; i <= (uint) DECIMAL_RESULT; i++) - { - if (found_types & (1 << i) && !cmp_items[i]) + for (i= 0; i <= (uint) DECIMAL_RESULT; i++) { - if ((Item_result)i == STRING_RESULT && - agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) - return; - if (!(cmp_items[i]= - cmp_item::get_comparator((Item_result)i, - cmp_collation.collation))) - return; + if (found_types & (1 << i) && !cmp_items[i]) + { + if ((Item_result)i == STRING_RESULT && + agg_arg_charsets(cmp_collation, args, arg_count, + MY_COLL_CMP_CONV, 1)) + return; + if (!cmp_items[i] && !(cmp_items[i]= + cmp_item::get_comparator((Item_result)i, + cmp_collation.collation))) + return; + } } } - } } max_length= 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2f45fcfb23b..8db962a4e2c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1186,7 +1186,7 @@ public: */ bool arg_types_compatible; Item_result left_result_type; - cmp_item *cmp_items[5]; /* One cmp_item for each result type */ + cmp_item *cmp_items[6]; /* One cmp_item for each result type */ DTCollation cmp_collation; Item_func_in(List &list) @@ -1207,7 +1207,7 @@ public: Item_int_func::cleanup(); delete array; array= 0; - for (i= 0; i <= (uint)DECIMAL_RESULT; i++) + for (i= 0; i <= (uint)DECIMAL_RESULT + 1; i++) { delete cmp_items[i]; cmp_items[i]= 0; @@ -1251,35 +1251,7 @@ public: void set(uint pos,Item *item); byte *get_value(Item *item); friend void Item_func_in::fix_length_and_dec(); - Item_resul result_type() { return ROW_RESULT; }; -}; - -class cmp_item_row :public cmp_item -{ - cmp_item **comparators; - uint n; -public: - cmp_item_row(): comparators(0), n(0) {} - ~cmp_item_row(); - void store_value(Item *item); - inline void alloc_comparators(); - int cmp(Item *arg); - int compare(cmp_item *arg); - cmp_item *make_same(); - void store_value_by_template(cmp_item *tmpl, Item *); - friend void Item_func_in::fix_length_and_dec(); -}; - - -class in_row :public in_vector -{ - cmp_item_row tmp; -public: - in_row(uint elements, Item *); - ~in_row(); - void set(uint pos,Item *item); - byte *get_value(Item *item); - friend void Item_func_in::fix_length_and_dec(); + Item_result result_type() { return ROW_RESULT; }; }; /* Functions used by where clause */