maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #10639
Re: MDEV-12514 Split Item_temporal_func::fix_length_and_dec()
Oops, forgot to attach the patch.
On 04/17/2017 03:20 PM, Alexander Barkov wrote:
> Hi Sanja,
>
>
> Please review a patch for MDEV-12514, also fixing this bug:
>
> MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a
> numeric field
>
>
> Thanks!
>
commit 0b59aa1a8567f4660715a24e5aa33a5016894ec8
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date: Mon Apr 17 15:09:19 2017 +0400
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)
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 54da823..a05c6a7 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -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;
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index e713233..6a7b7e7 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -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
#
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 6e0169d..e8d1d4e 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -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;
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index a19de83..1b355b7 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -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
diff --git a/sql/item_func.h b/sql/item_func.h
index 7f9321f..a367a0d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -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;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 174f8ff..a4a1f90 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 @@ 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();
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index f66c57e..40b8c16 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -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);
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 337111f..cf5e4e4 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -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;
}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 891c785..bd5290a 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -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
{
References