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; ...@@ -3210,3 +3210,48 @@ DROP TABLE t1,t2;
# #
# End of 10.1 tests # 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; ...@@ -3902,5 +3902,36 @@ SELECT 1 MOD COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' ERROR HY000: Illegal parameter data types bigint and geometry for operation '%'
DROP TABLE t1; 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 # End of 10.3 tests
# #
...@@ -1817,3 +1817,35 @@ DROP TABLE t1,t2; ...@@ -1817,3 +1817,35 @@ DROP TABLE t1,t2;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --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; ...@@ -2090,6 +2090,40 @@ SELECT 1 MOD COALESCE(a) FROM t1;
DROP TABLE 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 #
--echo # End of 10.3 tests --echo # End of 10.3 tests
......
...@@ -75,18 +75,10 @@ class Item_func :public Item_func_or_sum ...@@ -75,18 +75,10 @@ class Item_func :public Item_func_or_sum
{ {
return count_string_length(item, nitems); 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, void aggregate_attributes_temporal(uint int_part_length,
Item **item, uint nitems) 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; table_map not_null_tables_cache;
......
...@@ -1458,34 +1458,6 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) ...@@ -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) String *Item_temporal_func::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
...@@ -2009,8 +1981,8 @@ void Item_func_from_unixtime::fix_length_and_dec() ...@@ -2009,8 +1981,8 @@ void Item_func_from_unixtime::fix_length_and_dec()
THD *thd= current_thd; THD *thd= current_thd;
thd->time_zone_used= 1; thd->time_zone_used= 1;
tz= thd->variables.time_zone; tz= thd->variables.time_zone;
decimals= args[0]->decimals; fix_attributes_datetime_not_fixed_dec(args[0]->decimals);
Item_temporal_func::fix_length_and_dec(); maybe_null= true;
} }
...@@ -2039,8 +2011,8 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, ...@@ -2039,8 +2011,8 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec() void Item_func_convert_tz::fix_length_and_dec()
{ {
decimals= args[0]->temporal_precision(MYSQL_TYPE_DATETIME); fix_attributes_datetime(args[0]->temporal_precision(MYSQL_TYPE_DATETIME));
Item_temporal_func::fix_length_and_dec(); maybe_null= true;
} }
...@@ -2093,6 +2065,13 @@ void Item_date_add_interval::fix_length_and_dec() ...@@ -2093,6 +2065,13 @@ void Item_date_add_interval::fix_length_and_dec()
{ {
enum_field_types arg0_field_type; 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 The field type for the result of an Item_datefunc is defined as
follows: follows:
...@@ -2108,7 +2087,6 @@ void Item_date_add_interval::fix_length_and_dec() ...@@ -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, (This is because you can't know if the string contains a DATE,
MYSQL_TIME or DATETIME argument) MYSQL_TIME or DATETIME argument)
*/ */
set_handler_by_field_type(MYSQL_TYPE_STRING);
arg0_field_type= args[0]->field_type(); arg0_field_type= args[0]->field_type();
uint interval_dec= 0; uint interval_dec= 0;
if (int_type == INTERVAL_MICROSECOND || if (int_type == INTERVAL_MICROSECOND ||
...@@ -2121,30 +2099,47 @@ void Item_date_add_interval::fix_length_and_dec() ...@@ -2121,30 +2099,47 @@ void Item_date_add_interval::fix_length_and_dec()
if (arg0_field_type == MYSQL_TYPE_DATETIME || if (arg0_field_type == MYSQL_TYPE_DATETIME ||
arg0_field_type == MYSQL_TYPE_TIMESTAMP) arg0_field_type == MYSQL_TYPE_TIMESTAMP)
{ {
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec); uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
set_handler_by_field_type(MYSQL_TYPE_DATETIME); interval_dec);
set_handler(&type_handler_datetime);
fix_attributes_datetime(dec);
} }
else if (arg0_field_type == MYSQL_TYPE_DATE) else if (arg0_field_type == MYSQL_TYPE_DATE)
{ {
if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) 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 else
{ {
decimals= interval_dec; set_handler(&type_handler_datetime2);
set_handler_by_field_type(MYSQL_TYPE_DATETIME); fix_attributes_datetime(interval_dec);
} }
} }
else if (arg0_field_type == MYSQL_TYPE_TIME) 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) 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 else
set_handler_by_field_type(MYSQL_TYPE_DATETIME); {
set_handler(&type_handler_datetime2);
fix_attributes_datetime(dec);
}
} }
else 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) ...@@ -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() void Item_func_add_time::fix_length_and_dec()
{ {
enum_field_types arg0_field_type; 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 The field type for the result of an Item_func_add_time function is defined
as follows: as follows:
...@@ -2661,24 +2663,32 @@ void Item_func_add_time::fix_length_and_dec() ...@@ -2661,24 +2663,32 @@ void Item_func_add_time::fix_length_and_dec()
- Otherwise the result is MYSQL_TYPE_STRING - Otherwise the result is MYSQL_TYPE_STRING
*/ */
set_handler_by_field_type(MYSQL_TYPE_STRING);
arg0_field_type= args[0]->field_type(); arg0_field_type= args[0]->field_type();
if (arg0_field_type == MYSQL_TYPE_DATE || if (arg0_field_type == MYSQL_TYPE_DATE ||
arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_DATETIME ||
arg0_field_type == MYSQL_TYPE_TIMESTAMP || arg0_field_type == MYSQL_TYPE_TIMESTAMP ||
is_date) is_date)
{ {
set_handler_by_field_type(MYSQL_TYPE_DATETIME); uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME),
args[1]->temporal_precision(MYSQL_TYPE_TIME)); args[1]->temporal_precision(MYSQL_TYPE_TIME));
set_handler(&type_handler_datetime2);
fix_attributes_datetime(dec);
} }
else if (arg0_field_type == MYSQL_TYPE_TIME) else if (arg0_field_type == MYSQL_TYPE_TIME)
{ {
set_handler_by_field_type(MYSQL_TYPE_TIME); uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME),
args[1]->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) ...@@ -3169,6 +3179,14 @@ get_date_time_result_type(const char *format, uint length)
void Item_func_str_to_date::fix_length_and_dec() 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)) if (agg_arg_charsets(collation, args, 2, MY_COLL_ALLOW_CONV, 1))
return; return;
if (collation.collation->mbminlen > 1) if (collation.collation->mbminlen > 1)
...@@ -3180,8 +3198,10 @@ void Item_func_str_to_date::fix_length_and_dec() ...@@ -3180,8 +3198,10 @@ void Item_func_str_to_date::fix_length_and_dec()
#endif #endif
} }
set_handler_by_field_type(MYSQL_TYPE_DATETIME); maybe_null= true;
decimals= TIME_SECOND_PART_DIGITS; set_handler(&type_handler_datetime2);
fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
if ((const_item= args[1]->const_item())) if ((const_item= args[1]->const_item()))
{ {
char format_buff[64]; char format_buff[64];
...@@ -3195,25 +3215,29 @@ void Item_func_str_to_date::fix_length_and_dec() ...@@ -3195,25 +3215,29 @@ void Item_func_str_to_date::fix_length_and_dec()
get_date_time_result_type(format->ptr(), format->length()); get_date_time_result_type(format->ptr(), format->length());
switch (cached_format_type) { switch (cached_format_type) {
case DATE_ONLY: case DATE_ONLY:
set_handler_by_field_type(MYSQL_TYPE_DATE); set_handler(&type_handler_newdate);
fix_attributes_date();
break; break;
case TIME_MICROSECOND: case TIME_MICROSECOND:
decimals= 6; set_handler(&type_handler_time2);
/* fall through */ fix_attributes_time(TIME_SECOND_PART_DIGITS);
break;
case TIME_ONLY: case TIME_ONLY:
set_handler_by_field_type(MYSQL_TYPE_TIME); set_handler(&type_handler_time2);
fix_attributes_time(0);
break; break;
case DATE_TIME_MICROSECOND: case DATE_TIME_MICROSECOND:
decimals= 6; set_handler(&type_handler_datetime2);
/* fall through */ fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
break;
case DATE_TIME: case DATE_TIME:
set_handler_by_field_type(MYSQL_TYPE_DATETIME); set_handler(&type_handler_datetime2);
fix_attributes_datetime(0);
break; break;
} }
} }
} }
cached_timestamp_type= mysql_type_to_time_type(field_type()); 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 ...@@ -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); bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval);
class Item_func_period_add :public Item_int_func class Item_func_period_add :public Item_int_func
...@@ -531,7 +521,6 @@ class Item_func_time_to_sec :public Item_func_seconds_hybrid ...@@ -531,7 +521,6 @@ class Item_func_time_to_sec :public Item_func_seconds_hybrid
class Item_temporal_func: public Item_func class Item_temporal_func: public Item_func
{ {
sql_mode_t sql_mode;
public: public:
Item_temporal_func(THD *thd): Item_func(thd) {} Item_temporal_func(THD *thd): Item_func(thd) {}
Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {} Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {}
...@@ -549,7 +538,6 @@ class Item_temporal_func: public Item_func ...@@ -549,7 +538,6 @@ class Item_temporal_func: public Item_func
{ return tmp_table_field_from_field_type(table, false, false); } { return tmp_table_field_from_field_type(table, false, false); }
int save_in_field(Field *field, bool no_conversions) int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field, 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 ...@@ -557,22 +545,20 @@ class Item_temporal_func: public Item_func
Abstract class for functions returning TIME, DATE, DATETIME or string values, Abstract class for functions returning TIME, DATE, DATETIME or string values,
whose data type depends on parameters and is set at fix_fields time. whose data type depends on parameters and is set at fix_fields time.
*/ */
class Item_temporal_hybrid_func: public Item_temporal_func, class Item_temporal_hybrid_func: public Item_hybrid_func
public Type_handler_hybrid_field_type
{ {
protected: protected:
String ascii_buf; // Conversion buffer String ascii_buf; // Conversion buffer
public: public:
Item_temporal_hybrid_func(THD *thd, Item *a, Item *b): Item_temporal_hybrid_func(THD *thd, Item *a, Item *b):
Item_temporal_func(thd, a, b) {} Item_hybrid_func(thd, a, b) {}
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); } longlong val_int() { return val_int_from_date(); }
enum_field_types field_type() const double val_real() { return val_real_from_date(); }
{ return Type_handler_hybrid_field_type::field_type(); } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
enum Item_result result_type () const my_decimal *val_decimal(my_decimal *decimal_value)
{ return Type_handler_hybrid_field_type::result_type(); } { return val_decimal_from_date(decimal_value); }
enum Item_result cmp_type () const
{ return Type_handler_hybrid_field_type::cmp_type(); }
/** /**
Fix the returned timestamp to match field_type(), Fix the returned timestamp to match field_type(),
which is important for val_str(). which is important for val_str().
...@@ -599,6 +585,11 @@ class Item_datefunc :public Item_temporal_func ...@@ -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_temporal_func(thd, a) { }
Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { } Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; } 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 ...@@ -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) Item_func_curtime(THD *thd, uint dec): Item_timefunc(thd), last_query_id(0)
{ decimals= dec; } { decimals= dec; }
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
void fix_length_and_dec() { fix_attributes_time(decimals); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
/* /*
Abstract method that defines which time zone is used for conversion. Abstract method that defines which time zone is used for conversion.
...@@ -722,6 +714,7 @@ class Item_func_now :public Item_datetimefunc ...@@ -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) Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0)
{ decimals= dec; } { decimals= dec; }
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
void fix_length_and_dec() { fix_attributes_datetime(decimals); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg) bool check_vcol_func_processor(void *arg)
...@@ -886,8 +879,8 @@ class Item_func_sec_to_time :public Item_timefunc ...@@ -886,8 +879,8 @@ class Item_func_sec_to_time :public Item_timefunc
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
void fix_length_and_dec() void fix_length_and_dec()
{ {
decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS); fix_attributes_time(args[0]->decimals);
Item_timefunc::fix_length_and_dec(); maybe_null= true;
} }
const char *func_name() const { return "sec_to_time"; } const char *func_name() const { return "sec_to_time"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
...@@ -1066,11 +1059,12 @@ class Item_temporal_typecast: public Item_temporal_func ...@@ -1066,11 +1059,12 @@ class Item_temporal_typecast: public Item_temporal_func
Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {} Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {}
virtual const char *cast_type() const = 0; virtual const char *cast_type() const = 0;
void print(String *str, enum_query_type query_type); 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) if (decimals == NOT_FIXED_DEC)
decimals= args[0]->temporal_precision(field_type()); 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 ...@@ -1163,9 +1157,10 @@ class Item_func_timediff :public Item_timefunc
const char *func_name() const { return "timediff"; } const char *func_name() const { return "timediff"; }
void fix_length_and_dec() 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)); 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); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
...@@ -1180,8 +1175,8 @@ class Item_func_maketime :public Item_timefunc ...@@ -1180,8 +1175,8 @@ class Item_func_maketime :public Item_timefunc
{} {}
void fix_length_and_dec() void fix_length_and_dec()
{ {
decimals= MY_MIN(args[2]->decimals, TIME_SECOND_PART_DIGITS); fix_attributes_time(args[2]->decimals);
Item_timefunc::fix_length_and_dec(); maybe_null= true;
} }
const char *func_name() const { return "maketime"; } const char *func_name() const { return "maketime"; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
......
...@@ -26,14 +26,10 @@ static Type_handler_long type_handler_long; ...@@ -26,14 +26,10 @@ static Type_handler_long type_handler_long;
static Type_handler_int24 type_handler_int24; static Type_handler_int24 type_handler_int24;
static Type_handler_year type_handler_year; static Type_handler_year type_handler_year;
static Type_handler_time type_handler_time; static Type_handler_time type_handler_time;
static Type_handler_time2 type_handler_time2;
static Type_handler_date type_handler_date; 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_timestamp type_handler_timestamp;
static Type_handler_timestamp2 type_handler_timestamp2; static Type_handler_timestamp2 type_handler_timestamp2;
static Type_handler_olddecimal type_handler_olddecimal; 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_tiny_blob type_handler_tiny_blob;
static Type_handler_medium_blob type_handler_medium_blob; static Type_handler_medium_blob type_handler_medium_blob;
static Type_handler_long_blob type_handler_long_blob; static Type_handler_long_blob type_handler_long_blob;
...@@ -42,6 +38,7 @@ static Type_handler_blob type_handler_blob; ...@@ -42,6 +38,7 @@ static Type_handler_blob type_handler_blob;
Type_handler_null type_handler_null; Type_handler_null type_handler_null;
Type_handler_row type_handler_row; Type_handler_row type_handler_row;
Type_handler_string type_handler_string;
Type_handler_varchar type_handler_varchar; Type_handler_varchar type_handler_varchar;
Type_handler_longlong type_handler_longlong; Type_handler_longlong type_handler_longlong;
Type_handler_float type_handler_float; Type_handler_float type_handler_float;
...@@ -52,6 +49,10 @@ Type_handler_bit type_handler_bit; ...@@ -52,6 +49,10 @@ Type_handler_bit type_handler_bit;
Type_handler_enum type_handler_enum; Type_handler_enum type_handler_enum;
Type_handler_set type_handler_set; 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 #ifdef HAVE_SPATIAL
Type_handler_geometry type_handler_geometry; Type_handler_geometry type_handler_geometry;
#endif #endif
...@@ -1346,7 +1347,7 @@ bool Type_handler_date_common:: ...@@ -1346,7 +1347,7 @@ bool Type_handler_date_common::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
Item **items, uint nitems) const Item **items, uint nitems) const
{ {
func->set_attributes_temporal(MAX_DATE_WIDTH, 0); func->fix_attributes_date();
return false; return false;
} }
...@@ -2688,7 +2689,7 @@ bool Type_handler_numeric:: ...@@ -2688,7 +2689,7 @@ bool Type_handler_numeric::
bool Type_handler:: bool Type_handler::
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const 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; return false;
} }
...@@ -2696,7 +2697,7 @@ bool Type_handler:: ...@@ -2696,7 +2697,7 @@ bool Type_handler::
bool Type_handler:: bool Type_handler::
Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const 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; return false;
} }
...@@ -2705,7 +2706,7 @@ bool Type_handler:: ...@@ -2705,7 +2706,7 @@ bool Type_handler::
Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
const const
{ {
item->fix_length_and_dec_generic(); item->fix_length_and_dec_generic(MAX_DATETIME_WIDTH);
return false; return false;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "mysqld.h" #include "mysqld.h"
#include "sql_array.h" #include "sql_array.h"
#include "sql_const.h"
#include "my_time.h"
class Field; class Field;
class Item; class Item;
...@@ -261,6 +263,54 @@ class Type_std_attributes ...@@ -261,6 +263,54 @@ class Type_std_attributes
max_length= char_to_byte_length_safe(max_char_length_arg, max_length= char_to_byte_length_safe(max_char_length_arg,
collation.collation->mbmaxlen); 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 ...@@ -1585,6 +1635,7 @@ class Type_handler_hybrid_field_type
extern Type_handler_row type_handler_row; extern Type_handler_row type_handler_row;
extern Type_handler_null type_handler_null; extern Type_handler_null type_handler_null;
extern Type_handler_string type_handler_string;
extern Type_handler_varchar type_handler_varchar; extern Type_handler_varchar type_handler_varchar;
extern Type_handler_longlong type_handler_longlong; extern Type_handler_longlong type_handler_longlong;
extern Type_handler_float type_handler_float; extern Type_handler_float type_handler_float;
...@@ -1596,6 +1647,10 @@ extern Type_handler_bit type_handler_bit; ...@@ -1596,6 +1647,10 @@ extern Type_handler_bit type_handler_bit;
extern Type_handler_enum type_handler_enum; extern Type_handler_enum type_handler_enum;
extern Type_handler_set type_handler_set; 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 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