Commit e2b03cd3 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12514 Split Item_temporal_func::fix_length_and_dec() + MDEV-12515

This patch implements MDEV-12514 according to the task descriptions.
It automatically fixes:
MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a numeric field

Additionally:

a. Moves Item_func::set_attributes_temporal() to
   Type_str_attributes::fix_attributes_temporal(),
  which is a more proper place and name for it.

b. Continues replacing calls for:
     set_handler_by_field_type(MYSQL_TYPE_XXX)
   to corresponding:
     set_handler(&type_handler_xxx)
   which is faster.
   Note, we should eventually get rid of almost all set_handler_by_field_type().

c. Makes type_handler_string, type_handler_time2, type_handler_newdate,
   type_handler_datetime2 public.
   (all built-in handlers will become public eventually)

d. Removing Item_temporal_func::sql_mode, as it was not used.
parent 634f9186
......@@ -3210,3 +3210,48 @@ DROP TABLE t1,t2;
#
# End of 10.1 tests
#
#
# Start of 10.3 tests
#
#
# MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a numeric field
#
SET sql_mode='';
CREATE TABLE t1 AS SELECT
DATE_ADD('2001-01-01',INTERVAL 1 DAY) AS c1,
ADDTIME('10:20:30',1) AS c2;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(19) DEFAULT NULL,
`c2` varchar(26) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t1;
c1 c2
2001-01-02 10:20:31
DROP TABLE t1;
CREATE TABLE t2 (c INT);
INSERT INTO t2 SELECT DATE_ADD('2001-01-01',INTERVAL 1 DAY);
Warnings:
Warning 1265 Data truncated for column 'c' at row 1
INSERT INTO t2 VALUES ('2001-01-02');
Warnings:
Warning 1265 Data truncated for column 'c' at row 1
SELECT * FROM t2;
c
2001
2001
DROP TABLE t2;
CREATE TABLE t2 (a INT);
INSERT INTO t2 VALUES (ADDTIME('10:20:30',1));
Warnings:
Warning 1265 Data truncated for column 'a' at row 1
INSERT INTO t2 VALUES ('10:20:31');
Warnings:
Warning 1265 Data truncated for column 'a' at row 1
SELECT * FROM t2;
a
10
10
DROP TABLE t2;
SET sql_mode=DEFAULT;
......@@ -3902,5 +3902,36 @@ SELECT 1 MOD COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '%'
DROP TABLE t1;
#
# MDEV-12514 Split Item_temporal_func::fix_length_and_dec()
#
SELECT DATE_ADD(POINT(1,1), INTERVAL 10 DAY);
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT DATE_SUB(POINT(1,1), INTERVAL 10 DAY);
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT POINT(1,1) + INTERVAL 10 DAY;
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT POINT(1,1) - INTERVAL 10 DAY;
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT INTERVAL 10 DAY + POINT(1,1);
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT INTERVAL 10 DAY + POINT(1,1);
ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval'
SELECT ADDTIME(POINT(1,1), '10:10:10');
ERROR HY000: Illegal parameter data types geometry and varchar for operation 'add_time'
SELECT ADDTIME('10:10:10', POINT(1,1));
ERROR HY000: Illegal parameter data types varchar and geometry for operation 'add_time'
SELECT ADDTIME(POINT(1,1), TIME'10:10:10');
ERROR HY000: Illegal parameter data types geometry and time for operation 'add_time'
SELECT ADDTIME(TIME'10:10:10', POINT(1,1));
ERROR HY000: Illegal parameter data types time and geometry for operation 'add_time'
SELECT ADDTIME(POINT(1,1), TIMESTAMP'2001-01-01 10:10:10');
ERROR HY000: Illegal parameter data types geometry and datetime for operation 'add_time'
SELECT ADDTIME(TIMESTAMP'2001-01-01 10:10:10', POINT(1,1));
ERROR HY000: Illegal parameter data types datetime and geometry for operation 'add_time'
SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y');
ERROR HY000: Illegal parameter data types geometry and varchar for operation 'str_to_date'
SELECT STR_TO_DATE('2001-01-01', POINT(1,1));
ERROR HY000: Illegal parameter data types varchar and geometry for operation 'str_to_date'
#
# End of 10.3 tests
#
......@@ -1817,3 +1817,35 @@ DROP TABLE t1,t2;
--echo #
--echo # End of 10.1 tests
--echo #
--echo #
--echo # Start of 10.3 tests
--echo #
--echo #
--echo # MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a numeric field
--echo #
SET sql_mode='';
CREATE TABLE t1 AS SELECT
DATE_ADD('2001-01-01',INTERVAL 1 DAY) AS c1,
ADDTIME('10:20:30',1) AS c2;
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t2 (c INT);
INSERT INTO t2 SELECT DATE_ADD('2001-01-01',INTERVAL 1 DAY);
INSERT INTO t2 VALUES ('2001-01-02');
SELECT * FROM t2;
DROP TABLE t2;
CREATE TABLE t2 (a INT);
INSERT INTO t2 VALUES (ADDTIME('10:20:30',1));
INSERT INTO t2 VALUES ('10:20:31');
SELECT * FROM t2;
DROP TABLE t2;
SET sql_mode=DEFAULT;
......@@ -2090,6 +2090,40 @@ SELECT 1 MOD COALESCE(a) FROM t1;
DROP TABLE t1;
--echo #
--echo # MDEV-12514 Split Item_temporal_func::fix_length_and_dec()
--echo #
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT DATE_ADD(POINT(1,1), INTERVAL 10 DAY);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT DATE_SUB(POINT(1,1), INTERVAL 10 DAY);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) + INTERVAL 10 DAY;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) - INTERVAL 10 DAY;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT INTERVAL 10 DAY + POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT INTERVAL 10 DAY + POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME(POINT(1,1), '10:10:10');
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME('10:10:10', POINT(1,1));
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME(POINT(1,1), TIME'10:10:10');
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME(TIME'10:10:10', POINT(1,1));
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME(POINT(1,1), TIMESTAMP'2001-01-01 10:10:10');
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT ADDTIME(TIMESTAMP'2001-01-01 10:10:10', POINT(1,1));
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y');
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT STR_TO_DATE('2001-01-01', POINT(1,1));
--echo #
--echo # End of 10.3 tests
......
......@@ -75,18 +75,10 @@ class Item_func :public Item_func_or_sum
{
return count_string_length(item, nitems);
}
void set_attributes_temporal(uint int_part_length, uint dec)
{
collation.set_numeric();
unsigned_flag= 0;
decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS);
uint length= decimals + int_part_length + (dec ? 1 : 0);
fix_char_length(length);
}
void aggregate_attributes_temporal(uint int_part_length,
Item **item, uint nitems)
{
set_attributes_temporal(int_part_length, count_max_decimals(item, nitems));
fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems));
}
table_map not_null_tables_cache;
......
......@@ -1458,34 +1458,6 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
}
void Item_temporal_func::fix_length_and_dec()
{
uint char_length= mysql_temporal_int_part_length(field_type());
/*
We set maybe_null to 1 as default as any bad argument with date or
time can get us to return NULL.
*/
maybe_null= (arg_count > 0);
if (decimals)
{
if (decimals == NOT_FIXED_DEC)
char_length+= TIME_SECOND_PART_DIGITS + 1;
else
{
set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
char_length+= decimals + 1;
}
}
sql_mode= current_thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
collation.set(field_type() == MYSQL_TYPE_STRING ?
default_charset() : &my_charset_numeric,
field_type() == MYSQL_TYPE_STRING ?
DERIVATION_COERCIBLE : DERIVATION_NUMERIC,
MY_REPERTOIRE_ASCII);
fix_char_length(char_length);
}
String *Item_temporal_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
......@@ -2009,8 +1981,8 @@ void Item_func_from_unixtime::fix_length_and_dec()
THD *thd= current_thd;
thd->time_zone_used= 1;
tz= thd->variables.time_zone;
decimals= args[0]->decimals;
Item_temporal_func::fix_length_and_dec();
fix_attributes_datetime_not_fixed_dec(args[0]->decimals);
maybe_null= true;
}
......@@ -2039,8 +2011,8 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
{
decimals= args[0]->temporal_precision(MYSQL_TYPE_DATETIME);
Item_temporal_func::fix_length_and_dec();
fix_attributes_datetime(args[0]->temporal_precision(MYSQL_TYPE_DATETIME));
maybe_null= true;
}
......@@ -2093,6 +2065,13 @@ void Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
if (!args[0]->type_handler()->is_traditional_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
"interval", func_name());
return;
}
/*
The field type for the result of an Item_datefunc is defined as
follows:
......@@ -2108,7 +2087,6 @@ void Item_date_add_interval::fix_length_and_dec()
(This is because you can't know if the string contains a DATE,
MYSQL_TIME or DATETIME argument)
*/
set_handler_by_field_type(MYSQL_TYPE_STRING);
arg0_field_type= args[0]->field_type();
uint interval_dec= 0;
if (int_type == INTERVAL_MICROSECOND ||
......@@ -2121,30 +2099,47 @@ void Item_date_add_interval::fix_length_and_dec()
if (arg0_field_type == MYSQL_TYPE_DATETIME ||
arg0_field_type == MYSQL_TYPE_TIMESTAMP)
{
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec);
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
interval_dec);
set_handler(&type_handler_datetime);
fix_attributes_datetime(dec);
}
else if (arg0_field_type == MYSQL_TYPE_DATE)
{
if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
set_handler_by_field_type(arg0_field_type);
{
set_handler(&type_handler_newdate);
fix_attributes_date();
}
else
{
decimals= interval_dec;
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
set_handler(&type_handler_datetime2);
fix_attributes_datetime(interval_dec);
}
}
else if (arg0_field_type == MYSQL_TYPE_TIME)
{
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), interval_dec);
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), interval_dec);
if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH)
set_handler_by_field_type(arg0_field_type);
{
set_handler(&type_handler_time2);
fix_attributes_time(dec);
}
else
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
{
set_handler(&type_handler_datetime2);
fix_attributes_datetime(dec);
}
}
else
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec);
Item_temporal_func::fix_length_and_dec();
{
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
interval_dec);
set_handler(&type_handler_string);
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
}
maybe_null= true;
}
......@@ -2649,8 +2644,15 @@ bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
decimals= MY_MAX(args[0]->decimals, args[1]->decimals);
if (!args[0]->type_handler()->is_traditional_type() ||
!args[1]->type_handler()->is_traditional_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
args[1]->type_handler()->name().ptr(), func_name());
return;
}
/*
The field type for the result of an Item_func_add_time function is defined
as follows:
......@@ -2661,24 +2663,32 @@ void Item_func_add_time::fix_length_and_dec()
- Otherwise the result is MYSQL_TYPE_STRING
*/
set_handler_by_field_type(MYSQL_TYPE_STRING);
arg0_field_type= args[0]->field_type();
if (arg0_field_type == MYSQL_TYPE_DATE ||
arg0_field_type == MYSQL_TYPE_DATETIME ||
arg0_field_type == MYSQL_TYPE_TIMESTAMP ||
is_date)
{
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
args[1]->temporal_precision(MYSQL_TYPE_TIME));
set_handler(&type_handler_datetime2);
fix_attributes_datetime(dec);
}
else if (arg0_field_type == MYSQL_TYPE_TIME)
{
set_handler_by_field_type(MYSQL_TYPE_TIME);
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
args[1]->temporal_precision(MYSQL_TYPE_TIME));
set_handler(&type_handler_time2);
fix_attributes_time(dec);
}
else
{
uint dec= MY_MAX(args[0]->decimals, args[1]->decimals);
set_handler(&type_handler_string);
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
}
Item_temporal_func::fix_length_and_dec();
maybe_null= true;
}
/**
......@@ -3169,6 +3179,14 @@ get_date_time_result_type(const char *format, uint length)
void Item_func_str_to_date::fix_length_and_dec()
{
if (!args[0]->type_handler()->is_traditional_type() ||
!args[1]->type_handler()->is_traditional_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
args[1]->type_handler()->name().ptr(), func_name());
return;
}
if (agg_arg_charsets(collation, args, 2, MY_COLL_ALLOW_CONV, 1))
return;
if (collation.collation->mbminlen > 1)
......@@ -3180,8 +3198,10 @@ void Item_func_str_to_date::fix_length_and_dec()
#endif
}
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
decimals= TIME_SECOND_PART_DIGITS;
maybe_null= true;
set_handler(&type_handler_datetime2);
fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
if ((const_item= args[1]->const_item()))
{
char format_buff[64];
......@@ -3195,25 +3215,29 @@ void Item_func_str_to_date::fix_length_and_dec()
get_date_time_result_type(format->ptr(), format->length());
switch (cached_format_type) {
case DATE_ONLY:
set_handler_by_field_type(MYSQL_TYPE_DATE);
set_handler(&type_handler_newdate);
fix_attributes_date();
break;
case TIME_MICROSECOND:
decimals= 6;
/* fall through */
set_handler(&type_handler_time2);
fix_attributes_time(TIME_SECOND_PART_DIGITS);
break;
case TIME_ONLY:
set_handler_by_field_type(MYSQL_TYPE_TIME);
set_handler(&type_handler_time2);
fix_attributes_time(0);
break;
case DATE_TIME_MICROSECOND:
decimals= 6;
/* fall through */
set_handler(&type_handler_datetime2);
fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
break;
case DATE_TIME:
set_handler_by_field_type(MYSQL_TYPE_DATETIME);
set_handler(&type_handler_datetime2);
fix_attributes_datetime(0);
break;
}
}
}
cached_timestamp_type= mysql_type_to_time_type(field_type());
Item_temporal_func::fix_length_and_dec();
}
......
......@@ -31,16 +31,6 @@ enum date_time_format_types
};
static inline uint
mysql_temporal_int_part_length(enum enum_field_types mysql_type)
{
static uint max_time_type_width[5]=
{ MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH,
MAX_DATETIME_WIDTH, MIN_TIME_WIDTH };
return max_time_type_width[mysql_type_to_time_type(mysql_type)+2];
}
bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval);
class Item_func_period_add :public Item_int_func
......@@ -531,7 +521,6 @@ class Item_func_time_to_sec :public Item_func_seconds_hybrid
class Item_temporal_func: public Item_func
{
sql_mode_t sql_mode;
public:
Item_temporal_func(THD *thd): Item_func(thd) {}
Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {}
......@@ -549,7 +538,6 @@ class Item_temporal_func: public Item_func
{ return tmp_table_field_from_field_type(table, false, false); }
int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field, no_conversions); }
void fix_length_and_dec();
};
......@@ -557,22 +545,20 @@ class Item_temporal_func: public Item_func
Abstract class for functions returning TIME, DATE, DATETIME or string values,
whose data type depends on parameters and is set at fix_fields time.
*/
class Item_temporal_hybrid_func: public Item_temporal_func,
public Type_handler_hybrid_field_type
class Item_temporal_hybrid_func: public Item_hybrid_func
{
protected:
String ascii_buf; // Conversion buffer
public:
Item_temporal_hybrid_func(THD *thd, Item *a, Item *b):
Item_temporal_func(thd, a, b) {}
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
enum_field_types field_type() const
{ return Type_handler_hybrid_field_type::field_type(); }
enum Item_result result_type () const
{ return Type_handler_hybrid_field_type::result_type(); }
enum Item_result cmp_type () const
{ return Type_handler_hybrid_field_type::cmp_type(); }
Item_hybrid_func(thd, a, b) {}
longlong val_int() { return val_int_from_date(); }
double val_real() { return val_real_from_date(); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); }
/**
Fix the returned timestamp to match field_type(),
which is important for val_str().
......@@ -599,6 +585,11 @@ class Item_datefunc :public Item_temporal_func
Item_datefunc(THD *thd, Item *a): Item_temporal_func(thd, a) { }
Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
void fix_length_and_dec()
{
fix_attributes_date();
maybe_null= (arg_count > 0);
}
};
......@@ -635,6 +626,7 @@ class Item_func_curtime :public Item_timefunc
Item_func_curtime(THD *thd, uint dec): Item_timefunc(thd), last_query_id(0)
{ decimals= dec; }
bool fix_fields(THD *, Item **);
void fix_length_and_dec() { fix_attributes_time(decimals); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
/*
Abstract method that defines which time zone is used for conversion.
......@@ -722,6 +714,7 @@ class Item_func_now :public Item_datetimefunc
Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0)
{ decimals= dec; }
bool fix_fields(THD *, Item **);
void fix_length_and_dec() { fix_attributes_datetime(decimals); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg)
......@@ -886,8 +879,8 @@ class Item_func_sec_to_time :public Item_timefunc
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
void fix_length_and_dec()
{
decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS);
Item_timefunc::fix_length_and_dec();
fix_attributes_time(args[0]->decimals);
maybe_null= true;
}
const char *func_name() const { return "sec_to_time"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
......@@ -1066,11 +1059,12 @@ class Item_temporal_typecast: public Item_temporal_func
Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {}
virtual const char *cast_type() const = 0;
void print(String *str, enum_query_type query_type);
void fix_length_and_dec_generic()
void fix_length_and_dec_generic(uint int_part_len)
{
if (decimals == NOT_FIXED_DEC)
decimals= args[0]->temporal_precision(field_type());
Item_temporal_func::fix_length_and_dec();
fix_attributes_temporal(int_part_len, decimals);
maybe_null= true;
}
};
......@@ -1163,9 +1157,10 @@ class Item_func_timediff :public Item_timefunc
const char *func_name() const { return "timediff"; }
void fix_length_and_dec()
{
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
args[1]->temporal_precision(MYSQL_TYPE_TIME));
Item_timefunc::fix_length_and_dec();
fix_attributes_time(dec);
maybe_null= true;
}
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
......@@ -1180,8 +1175,8 @@ class Item_func_maketime :public Item_timefunc
{}
void fix_length_and_dec()
{
decimals= MY_MIN(args[2]->decimals, TIME_SECOND_PART_DIGITS);
Item_timefunc::fix_length_and_dec();
fix_attributes_time(args[2]->decimals);
maybe_null= true;
}
const char *func_name() const { return "maketime"; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
......
......@@ -26,14 +26,10 @@ static Type_handler_long type_handler_long;
static Type_handler_int24 type_handler_int24;
static Type_handler_year type_handler_year;
static Type_handler_time type_handler_time;
static Type_handler_time2 type_handler_time2;
static Type_handler_date type_handler_date;
static Type_handler_newdate type_handler_newdate;
static Type_handler_datetime2 type_handler_datetime2;
static Type_handler_timestamp type_handler_timestamp;
static Type_handler_timestamp2 type_handler_timestamp2;
static Type_handler_olddecimal type_handler_olddecimal;
static Type_handler_string type_handler_string;
static Type_handler_tiny_blob type_handler_tiny_blob;
static Type_handler_medium_blob type_handler_medium_blob;
static Type_handler_long_blob type_handler_long_blob;
......@@ -42,6 +38,7 @@ static Type_handler_blob type_handler_blob;
Type_handler_null type_handler_null;
Type_handler_row type_handler_row;
Type_handler_string type_handler_string;
Type_handler_varchar type_handler_varchar;
Type_handler_longlong type_handler_longlong;
Type_handler_float type_handler_float;
......@@ -52,6 +49,10 @@ Type_handler_bit type_handler_bit;
Type_handler_enum type_handler_enum;
Type_handler_set type_handler_set;
Type_handler_time2 type_handler_time2;
Type_handler_newdate type_handler_newdate;
Type_handler_datetime2 type_handler_datetime2;
#ifdef HAVE_SPATIAL
Type_handler_geometry type_handler_geometry;
#endif
......@@ -1346,7 +1347,7 @@ bool Type_handler_date_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item **items, uint nitems) const
{
func->set_attributes_temporal(MAX_DATE_WIDTH, 0);
func->fix_attributes_date();
return false;
}
......@@ -2688,7 +2689,7 @@ bool Type_handler_numeric::
bool Type_handler::
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
{
item->fix_length_and_dec_generic();
item->fix_length_and_dec_generic(MIN_TIME_WIDTH);
return false;
}
......@@ -2696,7 +2697,7 @@ bool Type_handler::
bool Type_handler::
Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
{
item->fix_length_and_dec_generic();
item->fix_length_and_dec_generic(MAX_DATE_WIDTH);
return false;
}
......@@ -2705,7 +2706,7 @@ bool Type_handler::
Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
const
{
item->fix_length_and_dec_generic();
item->fix_length_and_dec_generic(MAX_DATETIME_WIDTH);
return false;
}
......
......@@ -23,6 +23,8 @@
#include "mysqld.h"
#include "sql_array.h"
#include "sql_const.h"
#include "my_time.h"
class Field;
class Item;
......@@ -261,6 +263,54 @@ class Type_std_attributes
max_length= char_to_byte_length_safe(max_char_length_arg,
collation.collation->mbmaxlen);
}
void fix_char_length_temporal_not_fixed_dec(uint int_part_length, uint dec)
{
uint char_length= int_part_length;
if ((decimals= dec))
{
if (decimals == NOT_FIXED_DEC)
char_length+= TIME_SECOND_PART_DIGITS + 1;
else
{
set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
char_length+= decimals + 1;
}
}
fix_char_length(char_length);
}
void fix_attributes_temporal_not_fixed_dec(uint int_part_length, uint dec)
{
collation.set_numeric();
unsigned_flag= 0;
fix_char_length_temporal_not_fixed_dec(int_part_length, dec);
}
void fix_attributes_time_not_fixed_dec(uint dec)
{
fix_attributes_temporal_not_fixed_dec(MIN_TIME_WIDTH, dec);
}
void fix_attributes_datetime_not_fixed_dec(uint dec)
{
fix_attributes_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
}
void fix_attributes_temporal(uint int_part_length, uint dec)
{
collation.set_numeric();
unsigned_flag= 0;
decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS);
max_length= decimals + int_part_length + (dec ? 1 : 0);
}
void fix_attributes_date()
{
fix_attributes_temporal(MAX_DATE_WIDTH, 0);
}
void fix_attributes_time(uint dec)
{
fix_attributes_temporal(MIN_TIME_WIDTH, dec);
}
void fix_attributes_datetime(uint dec)
{
fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
}
};
......@@ -1585,6 +1635,7 @@ class Type_handler_hybrid_field_type
extern Type_handler_row type_handler_row;
extern Type_handler_null type_handler_null;
extern Type_handler_string type_handler_string;
extern Type_handler_varchar type_handler_varchar;
extern Type_handler_longlong type_handler_longlong;
extern Type_handler_float type_handler_float;
......@@ -1596,6 +1647,10 @@ extern Type_handler_bit type_handler_bit;
extern Type_handler_enum type_handler_enum;
extern Type_handler_set type_handler_set;
extern Type_handler_time2 type_handler_time2;
extern Type_handler_newdate type_handler_newdate;
extern Type_handler_datetime2 type_handler_datetime2;
class Type_aggregator
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment