diff options
author | Alexander Barkov <bar@mariadb.org> | 2016-11-25 07:40:10 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2016-12-16 18:23:20 +0400 |
commit | cb16d753b2db936afff844cca0dd434fa7fe736b (patch) | |
tree | 710867c377f49c3089f2cfff467a3e48050fe6cc | |
parent | 4b4efb04854388f525d6515e5f95ecb92d992b34 (diff) | |
download | mariadb-git-cb16d753b2db936afff844cca0dd434fa7fe736b.tar.gz |
MDEV-11337 Split Item::save_in_field() into virtual methods in Type_handler
Also fixes:
MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type)
MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)
This patch does the following:
1. Splits the function Item::save_in_field() into pieces:
- Item::save_str_in_field()
- Item::save_real_in_field()
- Item::save_decimal_in_field()
- Item::save_int_in_field()
2. Adds the missing "no_conversion" parameters to
Item::save_time_in_field() and Item::save_date_in_field(),
so this parameter is now correctly passed to
set_field_to_null_with_conversions().
This fixes the problem reported in 11333.
3. Introduces a new virtual method Type_handler::Item_save_in_field()
and uses the methods Item::save_xxx_in_field() from the implementations
of Type_handler_xxx::Item_save_in_field().
These changes additionally fix the problem reported in MDEV-11331,
as the old code erroneously handled expressions like
COALESE(datetime-expression) through the STRING_RESULT branch of
Item::save_in_field() and therefore they looked like string type expressions
for the target fields. Now such expressions are correctly handled by
Item::save_date_in_field().
-rw-r--r-- | mysql-test/r/default.result | 13 | ||||
-rw-r--r-- | mysql-test/r/type_datetime.result | 21 | ||||
-rw-r--r-- | mysql-test/r/type_timestamp.result | 32 | ||||
-rw-r--r-- | mysql-test/t/default.test | 2 | ||||
-rw-r--r-- | mysql-test/t/type_datetime.test | 21 | ||||
-rw-r--r-- | mysql-test/t/type_timestamp.test | 24 | ||||
-rw-r--r-- | sql/item.cc | 104 | ||||
-rw-r--r-- | sql/item.h | 11 | ||||
-rw-r--r-- | sql/item_timefunc.h | 2 | ||||
-rw-r--r-- | sql/sql_type.cc | 44 | ||||
-rw-r--r-- | sql/sql_type.h | 42 |
11 files changed, 241 insertions, 75 deletions
diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result index efc2ec640f3..fb203cd3141 100644 --- a/mysql-test/r/default.result +++ b/mysql-test/r/default.result @@ -991,14 +991,9 @@ t1 CREATE TABLE `t1` ( `a` decimal(30,6) DEFAULT coalesce(current_timestamp(6)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 VALUES(); -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 INSERT IGNORE INTO t1 VALUES(); -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 SET sql_mode = 'STRICT_ALL_TABLES'; INSERT INTO t1 VALUES(); -ERROR 01000: Data truncated for column 'a' at row 1 SET sql_mode = DEFAULT; DROP TABLE t1; # @@ -1011,8 +1006,6 @@ t1 CREATE TABLE `t1` ( `a` decimal(30,6) DEFAULT coalesce(curtime(6)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 VALUES(); -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 DROP TABLE t1; # # DECIMAL + CURRENT_DATE, no truncation @@ -1024,8 +1017,6 @@ t1 CREATE TABLE `t1` ( `a` decimal(30,6) DEFAULT coalesce(curdate()) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 VALUES(); -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 DROP TABLE t1; # # COALESCE for SQL Standard <datetime value function> @@ -1082,10 +1073,10 @@ t1 CREATE TABLE `t1` ( INSERT INTO t1 VALUES (); Warnings: Note 1265 Data truncated for column 'a' at row 1 -Warning 1265 Data truncated for column 'b' at row 1 +Note 1265 Data truncated for column 'b' at row 1 SELECT * FROM t1; a b -20010101102030 2001 +20010101102030 20010101102030 DROP TABLE t1; # # Check DEFAULT() function diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 8588ad185ed..0df6b2b04c3 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -1199,3 +1199,24 @@ DROP TABLE t1; # # End of 10.2 tests # +# +# Start of 10.3 tests +# +# +# MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type) +# +SET timestamp=UNIX_TIMESTAMP('2001-02-03 10:00:00'); +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES (TIME'10:20:30'); +INSERT INTO t1 VALUES (COALESCE(TIME'10:20:30')); +INSERT INTO t1 VALUES (LEAST(TIME'10:20:30',TIME'10:20:30')); +SELECT * FROM t1; +a +2001-02-03 10:20:30 +2001-02-03 10:20:30 +2001-02-03 10:20:30 +DROP TABLE t1; +SET timestamp=DEFAULT; +# +# End of 10.3 tests +# diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 93180218fe4..c5e41a237fc 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -950,3 +950,35 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-11333 MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR) +# +SELECT DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR); +DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR) +NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow +CREATE TABLE t1 (a TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Warning 1441 Datetime function: datetime field overflow +EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Warning 1441 Datetime function: datetime field overflow +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test index d9d7f429848..a81f4867add 100644 --- a/mysql-test/t/default.test +++ b/mysql-test/t/default.test @@ -756,11 +756,9 @@ DROP TABLE t1; CREATE TABLE t1 (a DECIMAL(30,6) DEFAULT COALESCE(CURRENT_TIMESTAMP(6))); SHOW CREATE TABLE t1; -# Same as insert into t1 values ("2016-06-05 12:54:52.342095"); INSERT INTO t1 VALUES(); INSERT IGNORE INTO t1 VALUES(); SET sql_mode = 'STRICT_ALL_TABLES'; ---error WARN_DATA_TRUNCATED INSERT INTO t1 VALUES(); SET sql_mode = DEFAULT; DROP TABLE t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index b16d426ab70..1809f304457 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -751,3 +751,24 @@ DROP TABLE t1; --echo # --echo # End of 10.2 tests --echo # + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type) +--echo # +SET timestamp=UNIX_TIMESTAMP('2001-02-03 10:00:00'); +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES (TIME'10:20:30'); +INSERT INTO t1 VALUES (COALESCE(TIME'10:20:30')); +INSERT INTO t1 VALUES (LEAST(TIME'10:20:30',TIME'10:20:30')); +SELECT * FROM t1; +DROP TABLE t1; +SET timestamp=DEFAULT; + + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 460769f8961..2dad92b6b90 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -555,3 +555,27 @@ let defval='0000-00-00 00:00:00'; --echo # --echo # End of 10.1 tests --echo # + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-11333 MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR) +--echo # + +SELECT DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR); +CREATE TABLE t1 (a TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03'); +EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR); +EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)); +DROP TABLE t1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/item.cc b/sql/item.cc index ead45f84305..64d6cb703bd 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -419,21 +419,21 @@ longlong Item::val_int_from_decimal() return result; } -int Item::save_time_in_field(Field *field) +int Item::save_time_in_field(Field *field, bool no_conversions) { MYSQL_TIME ltime; if (get_time(<ime)) - return set_field_to_null_with_conversions(field, 0); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); } -int Item::save_date_in_field(Field *field) +int Item::save_date_in_field(Field *field, bool no_conversions) { MYSQL_TIME ltime; if (get_date(<ime, sql_mode_for_dates(field->table->in_use))) - return set_field_to_null_with_conversions(field, 0); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); } @@ -6265,54 +6265,62 @@ int Item_null::save_safe_in_field(Field *field) Note: all Item_XXX::val_str(str) methods must NOT assume that str != str_value. For example, see fix for bug #44743. */ +int Item::save_str_in_field(Field *field, bool no_conversions) +{ + String *result; + CHARSET_INFO *cs= collation.collation; + char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns + str_value.set_quick(buff, sizeof(buff), cs); + result=val_str(&str_value); + if (null_value) + { + str_value.set_quick(0, 0, cs); + return set_field_to_null_with_conversions(field, no_conversions); + } -int Item::save_in_field(Field *field, bool no_conversions) + /* NOTE: If null_value == FALSE, "result" must be not NULL. */ + + field->set_notnull(); + int error= field->store(result->ptr(),result->length(),cs); + str_value.set_quick(0, 0, cs); + return error; +} + + +int Item::save_real_in_field(Field *field, bool no_conversions) { - int error; - if (result_type() == STRING_RESULT) - { - String *result; - CHARSET_INFO *cs= collation.collation; - char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns - str_value.set_quick(buff, sizeof(buff), cs); - result=val_str(&str_value); - if (null_value) - { - str_value.set_quick(0, 0, cs); - return set_field_to_null_with_conversions(field, no_conversions); - } + double nr= val_real(); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store(nr); +} - /* NOTE: If null_value == FALSE, "result" must be not NULL. */ - field->set_notnull(); - error=field->store(result->ptr(),result->length(),cs); - str_value.set_quick(0, 0, cs); - } - else if (result_type() == REAL_RESULT) - { - double nr= val_real(); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store(nr); - } - else if (result_type() == DECIMAL_RESULT) - { - my_decimal decimal_value; - my_decimal *value= val_decimal(&decimal_value); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store_decimal(value); - } - else - { - longlong nr=val_int(); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store(nr, unsigned_flag); - } +int Item::save_decimal_in_field(Field *field, bool no_conversions) +{ + my_decimal decimal_value; + my_decimal *value= val_decimal(&decimal_value); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store_decimal(value); +} + + +int Item::save_int_in_field(Field *field, bool no_conversions) +{ + longlong nr= val_int(); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store(nr, unsigned_flag); +} + + +int Item::save_in_field(Field *field, bool no_conversions) +{ + int error= type_handler()->Item_save_in_field(this, field, no_conversions); return error ? error : (field->table->in_use->is_error() ? 1 : 0); } diff --git a/sql/item.h b/sql/item.h index b08788903a8..1c910d16247 100644 --- a/sql/item.h +++ b/sql/item.h @@ -991,8 +991,13 @@ public: // Check NULL value for a TIME, DATE or DATETIME expression bool is_null_from_temporal(); - int save_time_in_field(Field *field); - int save_date_in_field(Field *field); + int save_time_in_field(Field *field, bool no_conversions); + int save_date_in_field(Field *field, bool no_conversions); + int save_str_in_field(Field *field, bool no_conversions); + int save_real_in_field(Field *field, bool no_conversions); + int save_int_in_field(Field *field, bool no_conversions); + int save_decimal_in_field(Field *field, bool no_conversions); + int save_str_value_in_field(Field *field, String *result); virtual Field *get_tmp_table_field() { return 0; } @@ -3459,7 +3464,7 @@ public: my_decimal *val_decimal(my_decimal *decimal_value) { return val_decimal_from_date(decimal_value); } int save_in_field(Field *field, bool no_conversions) - { return save_date_in_field(field); } + { return save_date_in_field(field, no_conversions); } }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index dafcdf64b45..ad92f50661b 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -548,7 +548,7 @@ public: Field *create_field_for_create_select(TABLE *table) { 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); } + { return save_date_in_field(field, no_conversions); } void fix_length_and_dec(); }; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index a80417f60b9..42aa37a19a7 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -640,3 +640,47 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table, metadata & 0x00ff/*pack_length()*/, ((const Field_enum*) target)->typelib, target->charset()); } + +/*************************************************************************/ + +int Type_handler_time_common::Item_save_in_field(Item *item, Field *field, + bool no_conversions) const +{ + return item->save_time_in_field(field, no_conversions); +} + +int Type_handler_temporal_with_date::Item_save_in_field(Item *item, + Field *field, + bool no_conversions) + const +{ + return item->save_date_in_field(field, no_conversions); +} + + +int Type_handler_string_result::Item_save_in_field(Item *item, Field *field, + bool no_conversions) const +{ + return item->save_str_in_field(field, no_conversions); +} + + +int Type_handler_real_result::Item_save_in_field(Item *item, Field *field, + bool no_conversions) const +{ + return item->save_real_in_field(field, no_conversions); +} + + +int Type_handler_decimal_result::Item_save_in_field(Item *item, Field *field, + bool no_conversions) const +{ + return item->save_decimal_in_field(field, no_conversions); +} + + +int Type_handler_int_result::Item_save_in_field(Item *item, Field *field, + bool no_conversions) const +{ + return item->save_int_in_field(field, no_conversions); +} diff --git a/sql/sql_type.h b/sql/sql_type.h index de5c31a87e1..0147ee5639b 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -272,6 +272,9 @@ public: virtual void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; + + virtual int Item_save_in_field(Item *item, Field *field, + bool no_conversions) const= 0; }; @@ -288,6 +291,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; }; @@ -303,6 +307,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; }; @@ -318,6 +323,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; }; @@ -349,6 +355,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; }; @@ -463,28 +470,43 @@ public: }; -class Type_handler_time: public Type_handler_temporal_result +class Type_handler_time_common: public Type_handler_temporal_result { public: - virtual ~Type_handler_time() {} + virtual ~Type_handler_time_common() { } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; +}; + + +class Type_handler_time: public Type_handler_time_common +{ +public: + virtual ~Type_handler_time() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_time2: public Type_handler_temporal_result +class Type_handler_time2: public Type_handler_time_common { public: virtual ~Type_handler_time2() {} - enum_field_types field_type() const { return MYSQL_TYPE_TIME; } enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_date: public Type_handler_temporal_result +class Type_handler_temporal_with_date: public Type_handler_temporal_result +{ +public: + virtual ~Type_handler_temporal_with_date() {} + int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; +}; + + +class Type_handler_date: public Type_handler_temporal_with_date { public: virtual ~Type_handler_date() {} @@ -494,7 +516,7 @@ public: }; -class Type_handler_newdate: public Type_handler_temporal_result +class Type_handler_newdate: public Type_handler_temporal_with_date { public: virtual ~Type_handler_newdate() {} @@ -504,7 +526,7 @@ public: }; -class Type_handler_datetime: public Type_handler_temporal_result +class Type_handler_datetime: public Type_handler_temporal_with_date { public: virtual ~Type_handler_datetime() {} @@ -514,7 +536,7 @@ public: }; -class Type_handler_datetime2: public Type_handler_temporal_result +class Type_handler_datetime2: public Type_handler_temporal_with_date { public: virtual ~Type_handler_datetime2() {} @@ -525,7 +547,7 @@ public: }; -class Type_handler_timestamp: public Type_handler_temporal_result +class Type_handler_timestamp: public Type_handler_temporal_with_date { public: virtual ~Type_handler_timestamp() {} @@ -535,7 +557,7 @@ public: }; -class Type_handler_timestamp2: public Type_handler_temporal_result +class Type_handler_timestamp2: public Type_handler_temporal_with_date { public: virtual ~Type_handler_timestamp2() {} |