summaryrefslogtreecommitdiff
path: root/sql/item_timefunc.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-04-19 05:20:19 +0400
committerAlexander Barkov <bar@mariadb.org>2017-04-19 05:20:19 +0400
commite2b03cd3b54f39e09bf20eef77effe1b53813f29 (patch)
tree4ac86a3a301c79b25ce497683d1416ecee822378 /sql/item_timefunc.cc
parent634f9186922d0decb597178fda15928d2b22f062 (diff)
downloadmariadb-git-e2b03cd3b54f39e09bf20eef77effe1b53813f29.tar.gz
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.
Diffstat (limited to 'sql/item_timefunc.cc')
-rw-r--r--sql/item_timefunc.cc144
1 files changed, 84 insertions, 60 deletions
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 174f8ffb9fa..a4a1f900fce 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -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 @@ err:
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();
}