mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge epotemkin@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into sunlight.local:/local_work/27216-bug-5.0-opt-mysql
This commit is contained in:
@ -4355,6 +4355,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
DBUG_ASSERT(param->buffer_length != 0);
|
||||
param->fetch_result= fetch_result_str;
|
||||
break;
|
||||
@ -4427,6 +4428,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_BIT:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
param->skip_result= skip_result_string;
|
||||
break;
|
||||
default:
|
||||
|
@ -481,7 +481,7 @@ str_to_date(a,b)
|
||||
create table t2 select str_to_date(a,b) from t1;
|
||||
describe t2;
|
||||
Field Type Null Key Default Extra
|
||||
str_to_date(a,b) binary(29) YES NULL
|
||||
str_to_date(a,b) datetime YES NULL
|
||||
select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
|
||||
str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2,
|
||||
str_to_date("2003-01-02", "%Y-%m-%d") as f3,
|
||||
|
@ -427,3 +427,64 @@ f1
|
||||
Warnings:
|
||||
Warning 1292 Incorrect datetime value: '2007010100000' for column 'f1' at row 1
|
||||
drop table t1;
|
||||
#
|
||||
# Bug#27216: functions with parameters of different date types may
|
||||
# return wrong type of the result.
|
||||
#
|
||||
create table t1 (f1 date, f2 datetime, f3 varchar(20));
|
||||
create table t2 as select coalesce(f1,f1) as f4 from t1;
|
||||
desc t2;
|
||||
Field Type Null Key Default Extra
|
||||
f4 date YES NULL
|
||||
create table t3 as select coalesce(f1,f2) as f4 from t1;
|
||||
desc t3;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t4 as select coalesce(f2,f2) as f4 from t1;
|
||||
desc t4;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t5 as select coalesce(f1,f3) as f4 from t1;
|
||||
desc t5;
|
||||
Field Type Null Key Default Extra
|
||||
f4 varbinary(20) YES NULL
|
||||
create table t6 as select coalesce(f2,f3) as f4 from t1;
|
||||
desc t6;
|
||||
Field Type Null Key Default Extra
|
||||
f4 varbinary(20) YES NULL
|
||||
create table t7 as select coalesce(makedate(1997,1),f2) as f4 from t1;
|
||||
desc t7;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t8 as select coalesce(cast('01-01-01' as datetime),f2) as f4
|
||||
from t1;
|
||||
desc t8;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t9 as select case when 1 then cast('01-01-01' as date)
|
||||
when 0 then cast('01-01-01' as date) end as f4 from t1;
|
||||
desc t9;
|
||||
Field Type Null Key Default Extra
|
||||
f4 date YES NULL
|
||||
create table t10 as select case when 1 then cast('01-01-01' as datetime)
|
||||
when 0 then cast('01-01-01' as datetime) end as f4 from t1;
|
||||
desc t10;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t11 as select if(1, cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t11;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t12 as select least(cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t12;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
create table t13 as select ifnull(cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t13;
|
||||
Field Type Null Key Default Extra
|
||||
f4 datetime YES NULL
|
||||
drop tables t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13;
|
||||
###################################################################
|
||||
|
@ -282,3 +282,41 @@ select * from t1 where f1 between 20020101 and 20070101000000;
|
||||
select * from t1 where f1 between 2002010 and 20070101000000;
|
||||
select * from t1 where f1 between 20020101 and 2007010100000;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#27216: functions with parameters of different date types may
|
||||
--echo # return wrong type of the result.
|
||||
--echo #
|
||||
create table t1 (f1 date, f2 datetime, f3 varchar(20));
|
||||
create table t2 as select coalesce(f1,f1) as f4 from t1;
|
||||
desc t2;
|
||||
create table t3 as select coalesce(f1,f2) as f4 from t1;
|
||||
desc t3;
|
||||
create table t4 as select coalesce(f2,f2) as f4 from t1;
|
||||
desc t4;
|
||||
create table t5 as select coalesce(f1,f3) as f4 from t1;
|
||||
desc t5;
|
||||
create table t6 as select coalesce(f2,f3) as f4 from t1;
|
||||
desc t6;
|
||||
create table t7 as select coalesce(makedate(1997,1),f2) as f4 from t1;
|
||||
desc t7;
|
||||
create table t8 as select coalesce(cast('01-01-01' as datetime),f2) as f4
|
||||
from t1;
|
||||
desc t8;
|
||||
create table t9 as select case when 1 then cast('01-01-01' as date)
|
||||
when 0 then cast('01-01-01' as date) end as f4 from t1;
|
||||
desc t9;
|
||||
create table t10 as select case when 1 then cast('01-01-01' as datetime)
|
||||
when 0 then cast('01-01-01' as datetime) end as f4 from t1;
|
||||
desc t10;
|
||||
create table t11 as select if(1, cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t11;
|
||||
create table t12 as select least(cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t12;
|
||||
create table t13 as select ifnull(cast('01-01-01' as datetime),
|
||||
cast('01-01-01' as date)) as f4 from t1;
|
||||
desc t13;
|
||||
drop tables t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13;
|
||||
--echo ###################################################################
|
||||
|
@ -147,6 +147,36 @@ static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Aggregates field types from the array of items.
|
||||
|
||||
@param[in] items array of items to aggregate the type from
|
||||
@paran[in] nitems number of items in the array
|
||||
|
||||
@details This function aggregates field types from the array of items.
|
||||
Found type is supposed to be used later as the result field type
|
||||
of a multi-argument function.
|
||||
Aggregation itself is performed by the Field::field_type_merge()
|
||||
function.
|
||||
|
||||
@note The term "aggregation" is used here in the sense of inferring the
|
||||
result type of a function from its argument types.
|
||||
|
||||
@return aggregated field type.
|
||||
*/
|
||||
|
||||
enum_field_types agg_field_type(Item **items, uint nitems)
|
||||
{
|
||||
uint i;
|
||||
if (!nitems || items[0]->result_type() == ROW_RESULT )
|
||||
return (enum_field_types)-1;
|
||||
enum_field_types res= items[0]->field_type();
|
||||
for (i= 1 ; i < nitems ; i++)
|
||||
res= Field::field_type_merge(res, items[i]->field_type());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
|
||||
const char *fname)
|
||||
{
|
||||
@ -2009,9 +2039,7 @@ Item_func_ifnull::fix_length_and_dec()
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
cached_field_type= args[0]->field_type();
|
||||
if (cached_field_type != args[1]->field_type())
|
||||
cached_field_type= Item_func::field_type();
|
||||
cached_field_type= agg_field_type(args, 2);
|
||||
}
|
||||
|
||||
|
||||
@ -2159,11 +2187,13 @@ Item_func_if::fix_length_and_dec()
|
||||
{
|
||||
cached_result_type= arg2_type;
|
||||
collation.set(args[2]->collation.collation);
|
||||
cached_field_type= args[2]->field_type();
|
||||
}
|
||||
else if (null2)
|
||||
{
|
||||
cached_result_type= arg1_type;
|
||||
collation.set(args[1]->collation.collation);
|
||||
cached_field_type= args[1]->field_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2177,6 +2207,7 @@ Item_func_if::fix_length_and_dec()
|
||||
{
|
||||
collation.set(&my_charset_bin); // Number
|
||||
}
|
||||
cached_field_type= agg_field_type(args + 1, 2);
|
||||
}
|
||||
|
||||
if ((cached_result_type == DECIMAL_RESULT )
|
||||
@ -2556,7 +2587,7 @@ void Item_func_case::fix_length_and_dec()
|
||||
agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV, 1))
|
||||
return;
|
||||
|
||||
|
||||
cached_field_type= agg_field_type(agg, nagg);
|
||||
/*
|
||||
Aggregate first expression and all THEN expression types
|
||||
and collations when string comparison
|
||||
@ -2695,6 +2726,7 @@ 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);
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
|
@ -640,6 +640,7 @@ public:
|
||||
class Item_func_coalesce :public Item_func_numhybrid
|
||||
{
|
||||
protected:
|
||||
enum_field_types cached_field_type;
|
||||
Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
|
||||
public:
|
||||
Item_func_coalesce(List<Item> &list) :Item_func_numhybrid(list) {}
|
||||
@ -652,13 +653,13 @@ public:
|
||||
enum Item_result result_type () const { return hybrid_type; }
|
||||
const char *func_name() const { return "coalesce"; }
|
||||
table_map not_null_tables() const { return 0; }
|
||||
enum_field_types field_type() const { return cached_field_type; }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_ifnull :public Item_func_coalesce
|
||||
{
|
||||
protected:
|
||||
enum_field_types cached_field_type;
|
||||
bool field_type_defined;
|
||||
public:
|
||||
Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {}
|
||||
@ -677,6 +678,7 @@ public:
|
||||
class Item_func_if :public Item_func
|
||||
{
|
||||
enum Item_result cached_result_type;
|
||||
enum_field_types cached_field_type;
|
||||
public:
|
||||
Item_func_if(Item *a,Item *b,Item *c)
|
||||
:Item_func(a,b,c), cached_result_type(INT_RESULT)
|
||||
@ -686,6 +688,7 @@ public:
|
||||
String *val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type () const { return cached_result_type; }
|
||||
enum_field_types field_type() const { return cached_field_type; }
|
||||
bool fix_fields(THD *, Item **);
|
||||
void fix_length_and_dec();
|
||||
uint decimal_precision() const;
|
||||
@ -722,6 +725,7 @@ class Item_func_case :public Item_func
|
||||
uint ncases;
|
||||
Item_result cmp_type;
|
||||
DTCollation cmp_collation;
|
||||
enum_field_types cached_field_type;
|
||||
public:
|
||||
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
|
||||
:Item_func(), first_expr_num(-1), else_expr_num(-1),
|
||||
@ -749,6 +753,7 @@ public:
|
||||
uint decimal_precision() const;
|
||||
table_map not_null_tables() const { return 0; }
|
||||
enum Item_result result_type () const { return cached_result_type; }
|
||||
enum_field_types field_type() const { return cached_field_type; }
|
||||
const char *func_name() const { return "case"; }
|
||||
void print(String *str);
|
||||
Item *find_item(String *str);
|
||||
@ -1382,6 +1387,7 @@ public:
|
||||
bool subst_argument_checker(byte **arg) { return TRUE; }
|
||||
Item *compile(Item_analyzer analyzer, byte **arg_p,
|
||||
Item_transformer transformer, byte *arg_t);
|
||||
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -2243,6 +2243,7 @@ void Item_func_min_max::fix_length_and_dec()
|
||||
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
|
||||
max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
|
||||
unsigned_flag);
|
||||
cached_field_type= agg_field_type(args, arg_count);
|
||||
}
|
||||
|
||||
|
||||
|
@ -692,7 +692,8 @@ class Item_func_min_max :public Item_func
|
||||
/* An item used for issuing warnings while string to DATETIME conversion. */
|
||||
Item *datetime_item;
|
||||
THD *thd;
|
||||
|
||||
protected:
|
||||
enum_field_types cached_field_type;
|
||||
public:
|
||||
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
|
||||
cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
|
||||
@ -705,6 +706,7 @@ public:
|
||||
enum Item_result result_type () const { return cmp_type; }
|
||||
bool result_as_longlong() { return compare_as_dates; };
|
||||
uint cmp_datetimes(ulonglong *value);
|
||||
enum_field_types field_type() const { return cached_field_type; }
|
||||
};
|
||||
|
||||
class Item_func_min :public Item_func_min_max
|
||||
|
@ -3310,7 +3310,7 @@ void Item_func_str_to_date::fix_length_and_dec()
|
||||
String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
|
||||
maybe_null= 1;
|
||||
decimals=0;
|
||||
cached_field_type= MYSQL_TYPE_STRING;
|
||||
cached_field_type= MYSQL_TYPE_DATETIME;
|
||||
max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
|
||||
cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
|
||||
format= args[1]->val_str(&format_str);
|
||||
|
@ -1220,6 +1220,7 @@ my_bool mysql_rm_tmp_tables(void);
|
||||
|
||||
/* item_func.cc */
|
||||
extern bool check_reserved_words(LEX_STRING *name);
|
||||
extern enum_field_types agg_field_type(Item **items, uint nitems);
|
||||
|
||||
/* strfunc.cc */
|
||||
ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
|
||||
|
@ -824,6 +824,7 @@ bool Protocol_simple::store(const char *from, uint length,
|
||||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
|
||||
field_types[field_pos] == MYSQL_TYPE_BIT ||
|
||||
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
|
||||
field_types[field_pos] == MYSQL_TYPE_NEWDATE ||
|
||||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
|
||||
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
|
||||
field_pos++;
|
||||
|
@ -3134,7 +3134,10 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
create_field *cr_field;
|
||||
Field *field, *def_field;
|
||||
if (item->type() == Item::FUNC_ITEM)
|
||||
field= item->tmp_table_field(&tmp_table);
|
||||
if (item->result_type() != STRING_RESULT)
|
||||
field= item->tmp_table_field(&tmp_table);
|
||||
else
|
||||
field= item->tmp_table_field_from_field_type(&tmp_table);
|
||||
else
|
||||
field= create_tmp_field(thd, &tmp_table, item, item->type(),
|
||||
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0,
|
||||
|
Reference in New Issue
Block a user