diff options
-rw-r--r-- | include/my_time.h | 7 | ||||
-rw-r--r-- | mysql-test/r/dyncol.result | 2 | ||||
-rw-r--r-- | mysql-test/r/temporal_literal.result | 84 | ||||
-rw-r--r-- | mysql-test/r/type_datetime.result | 6 | ||||
-rw-r--r-- | mysql-test/t/temporal_literal.test | 24 | ||||
-rw-r--r-- | sql-common/my_time.c | 2 | ||||
-rw-r--r-- | sql/field.cc | 26 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/item_create.cc | 22 | ||||
-rw-r--r-- | sql/sql_error.h | 10 | ||||
-rw-r--r-- | sql/sql_time.cc | 4 |
11 files changed, 156 insertions, 33 deletions
diff --git a/include/my_time.h b/include/my_time.h index 4991d996258..67aa9a27f7f 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -69,6 +69,13 @@ extern uchar days_in_month[]; #define MYSQL_TIME_WARN_TRUNCATED 1 #define MYSQL_TIME_WARN_OUT_OF_RANGE 2 +#define MYSQL_TIME_NOTE_TRUNCATED 16 + +#define MYSQL_TIME_WARN_WARNINGS (MYSQL_TIME_WARN_TRUNCATED|MYSQL_TIME_WARN_OUT_OF_RANGE) +#define MYSQL_TIME_WARN_NOTES (MYSQL_TIME_NOTE_TRUNCATED) + +#define MYSQL_TIME_WARN_HAVE_WARNINGS(x) test((x) & MYSQL_TIME_WARN_WARNINGS) +#define MYSQL_TIME_WARN_HAVE_NOTES(x) test((x) & MYSQL_TIME_WARN_NOTES) /* Limits for the TIME data type */ #define TIME_MAX_HOUR 838 diff --git a/mysql-test/r/dyncol.result b/mysql-test/r/dyncol.result index c5040728af7..fa3f2234b7b 100644 --- a/mysql-test/r/dyncol.result +++ b/mysql-test/r/dyncol.result @@ -562,7 +562,7 @@ select column_get(column_create(1, "2011-04-05 8:46:06.12345678" AS datetime(6)) column_get(column_create(1, "2011-04-05 8:46:06.12345678" AS datetime(6)), 1 as decimal(32,8)) 20110405084606.12345600 Warnings: -Warning 1292 Truncated incorrect datetime value: '2011-04-05 8:46:06.12345678' +Note 1292 Truncated incorrect datetime value: '2011-04-05 8:46:06.12345678' select column_get(column_create(1, NULL as decimal), 1 as decimal(32,10)); column_get(column_create(1, NULL as decimal), 1 as decimal(32,10)) NULL diff --git a/mysql-test/r/temporal_literal.result b/mysql-test/r/temporal_literal.result index 84749302337..f8bc6510df0 100644 --- a/mysql-test/r/temporal_literal.result +++ b/mysql-test/r/temporal_literal.result @@ -291,24 +291,33 @@ SELECT TIMESTAMP'2001-01-00 00:00:00.999999'; TIMESTAMP'2001-01-00 00:00:00.999999' 2001-01-00 00:00:00.999999 SELECT TIMESTAMP'2001-00-00 00:00:00.9999999'; -ERROR HY000: Incorrect DATETIME value: '2001-00-00 00:00:00.9999999' +TIMESTAMP'2001-00-00 00:00:00.9999999' +2001-00-00 00:00:00.999999 +Warnings: +Note 1292 Truncated incorrect datetime value: '2001-00-00 00:00:00.9999999' SELECT TIMESTAMP'2001-00-01 00:00:00.9999999'; -ERROR HY000: Incorrect DATETIME value: '2001-00-01 00:00:00.9999999' +TIMESTAMP'2001-00-01 00:00:00.9999999' +2001-00-01 00:00:00.999999 +Warnings: +Note 1292 Truncated incorrect datetime value: '2001-00-01 00:00:00.9999999' SELECT TIMESTAMP'2001-01-00 00:00:00.9999999'; -ERROR HY000: Incorrect DATETIME value: '2001-01-00 00:00:00.9999999' +TIMESTAMP'2001-01-00 00:00:00.9999999' +2001-01-00 00:00:00.999999 +Warnings: +Note 1292 Truncated incorrect datetime value: '2001-01-00 00:00:00.9999999' # # String literal with bad dates and nanoseconds to DATETIME(N) # CREATE TABLE t1 (a DATETIME(6)); INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 SELECT * FROM t1; a 2001-00-00 00:00:00.999999 @@ -318,13 +327,13 @@ DROP TABLE t1; CREATE TABLE t1 (a DATETIME(5)); INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 SELECT * FROM t1; a 2001-00-00 00:00:00.99999 @@ -334,13 +343,13 @@ DROP TABLE t1; CREATE TABLE t1 (a DATETIME); INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999'); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 1 SELECT * FROM t1; a 2001-00-00 00:00:00 @@ -414,3 +423,54 @@ SELECT 'a' LIKE 'a' ESCAPE TIMESTAMP'2001-01-01 00:00:00'; ERROR HY000: Incorrect arguments to ESCAPE SELECT 'a' LIKE 'a' ESCAPE TIME'00:00:00'; ERROR HY000: Incorrect arguments to ESCAPE +# +# MDEV-4871 Temporal literals do not accept nanoseconds +# +SELECT TIME'10:10:10.1234567'; +TIME'10:10:10.1234567' +10:10:10.123456 +Warnings: +Note 1292 Truncated incorrect time value: '10:10:10.1234567' +SELECT TIME('10:10:10.1234567'); +TIME('10:10:10.1234567') +10:10:10.123456 +Warnings: +Note 1292 Truncated incorrect time value: '10:10:10.1234567' +SELECT TIME'10:10:10.123456xyz'; +ERROR HY000: Incorrect TIME value: '10:10:10.123456xyz' +SELECT TIME'10:10:10.1234567xyz'; +ERROR HY000: Incorrect TIME value: '10:10:10.1234567xyz' +SELECT TIME('10:10:10.123456xyz'); +TIME('10:10:10.123456xyz') +10:10:10.123456 +Warnings: +Warning 1292 Truncated incorrect time value: '10:10:10.123456xyz' +SELECT TIME('10:10:10.1234567xyz'); +TIME('10:10:10.1234567xyz') +10:10:10.123456 +Warnings: +Warning 1292 Truncated incorrect time value: '10:10:10.1234567xyz' +SELECT TIMESTAMP'2001-01-01 10:10:10.1234567'; +TIMESTAMP'2001-01-01 10:10:10.1234567' +2001-01-01 10:10:10.123456 +Warnings: +Note 1292 Truncated incorrect datetime value: '2001-01-01 10:10:10.1234567' +SELECT TIMESTAMP('2001-01-01 10:10:10.1234567'); +TIMESTAMP('2001-01-01 10:10:10.1234567') +2001-01-01 10:10:10.123456 +Warnings: +Note 1292 Truncated incorrect datetime value: '2001-01-01 10:10:10.1234567' +SELECT TIMESTAMP'2001-01-01 10:10:10.123456xyz'; +ERROR HY000: Incorrect DATETIME value: '2001-01-01 10:10:10.123456xyz' +SELECT TIMESTAMP'2001-01-01 10:10:10.1234567xyz'; +ERROR HY000: Incorrect DATETIME value: '2001-01-01 10:10:10.1234567xyz' +SELECT TIMESTAMP('2001-01-01 10:10:10.123456xyz'); +TIMESTAMP('2001-01-01 10:10:10.123456xyz') +2001-01-01 10:10:10.123456 +Warnings: +Warning 1292 Truncated incorrect datetime value: '2001-01-01 10:10:10.123456xyz' +SELECT TIMESTAMP('2001-01-01 10:10:10.1234567xyz'); +TIMESTAMP('2001-01-01 10:10:10.1234567xyz') +2001-01-01 10:10:10.123456 +Warnings: +Warning 1292 Truncated incorrect datetime value: '2001-01-01 10:10:10.1234567xyz' diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 1b53f92f82a..561f80a62ce 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -627,12 +627,12 @@ SELECT CAST(CAST('2006-08-10 10:11:12.0123450' AS DATETIME(6)) AS DECIMAL(30,7)) CAST(CAST('2006-08-10 10:11:12.0123450' AS DATETIME(6)) AS DECIMAL(30,7)) 20060810101112.0123450 Warnings: -Warning 1292 Truncated incorrect datetime value: '2006-08-10 10:11:12.0123450' +Note 1292 Truncated incorrect datetime value: '2006-08-10 10:11:12.0123450' SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.0123450' AS DATETIME(6)) AS DECIMAL(30,7)); CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.0123450' AS DATETIME(6)) AS DECIMAL(30,7)) 20060810101112.0123450 Warnings: -Warning 1292 Truncated incorrect datetime value: '00000002006-000008-0000010 000010:0000011:00000012.0123450' +Note 1292 Truncated incorrect datetime value: '00000002006-000008-0000010 000010:0000011:00000012.0123450' SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.012345' AS DATETIME(6)) AS DECIMAL(30,7)); CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.012345' AS DATETIME(6)) AS DECIMAL(30,7)) 20060810101112.0123450 @@ -640,7 +640,7 @@ SELECT CAST(CAST('2008-07-29T10:42:51.1234567' AS DateTime(6)) AS DECIMAL(30,7)) CAST(CAST('2008-07-29T10:42:51.1234567' AS DateTime(6)) AS DECIMAL(30,7)) 20080729104251.1234560 Warnings: -Warning 1292 Truncated incorrect datetime value: '2008-07-29T10:42:51.1234567' +Note 1292 Truncated incorrect datetime value: '2008-07-29T10:42:51.1234567' # # Bug#59173: Failure to handle DATE(TIME) values where Year, Month or # Day is ZERO diff --git a/mysql-test/t/temporal_literal.test b/mysql-test/t/temporal_literal.test index 5d67f64a6f5..d5beabcf1c1 100644 --- a/mysql-test/t/temporal_literal.test +++ b/mysql-test/t/temporal_literal.test @@ -155,11 +155,8 @@ EXPLAIN EXTENDED SELECT TIMESTAMP'2010-01-01 10:10:10'; SELECT TIMESTAMP'2001-00-00 00:00:00.999999'; SELECT TIMESTAMP'2001-00-01 00:00:00.999999'; SELECT TIMESTAMP'2001-01-00 00:00:00.999999'; ---error ER_WRONG_VALUE SELECT TIMESTAMP'2001-00-00 00:00:00.9999999'; ---error ER_WRONG_VALUE SELECT TIMESTAMP'2001-00-01 00:00:00.9999999'; ---error ER_WRONG_VALUE SELECT TIMESTAMP'2001-01-00 00:00:00.9999999'; --echo # @@ -215,3 +212,24 @@ SELECT 'a' LIKE 'a' ESCAPE DATE'2001-01-01'; SELECT 'a' LIKE 'a' ESCAPE TIMESTAMP'2001-01-01 00:00:00'; --error ER_WRONG_ARGUMENTS SELECT 'a' LIKE 'a' ESCAPE TIME'00:00:00'; + +--echo # +--echo # MDEV-4871 Temporal literals do not accept nanoseconds +--echo # +SELECT TIME'10:10:10.1234567'; +SELECT TIME('10:10:10.1234567'); +--error ER_WRONG_VALUE +SELECT TIME'10:10:10.123456xyz'; +--error ER_WRONG_VALUE +SELECT TIME'10:10:10.1234567xyz'; +SELECT TIME('10:10:10.123456xyz'); +SELECT TIME('10:10:10.1234567xyz'); + +SELECT TIMESTAMP'2001-01-01 10:10:10.1234567'; +SELECT TIMESTAMP('2001-01-01 10:10:10.1234567'); +--error ER_WRONG_VALUE +SELECT TIMESTAMP'2001-01-01 10:10:10.123456xyz'; +--error ER_WRONG_VALUE +SELECT TIMESTAMP'2001-01-01 10:10:10.1234567xyz'; +SELECT TIMESTAMP('2001-01-01 10:10:10.123456xyz'); +SELECT TIMESTAMP('2001-01-01 10:10:10.1234567xyz'); diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 75b94d14ac4..0e8a1098e55 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -239,7 +239,7 @@ static void get_microseconds(ulong *val, MYSQL_TIME_STATUS *status, else *val= tmp; if (skip_digits(str, end)) - status->warnings|= MYSQL_TIME_WARN_TRUNCATED; + status->warnings|= MYSQL_TIME_NOTE_TRUNCATED; } diff --git a/sql/field.cc b/sql/field.cc index bea8062ea32..81b5a66d908 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4593,19 +4593,25 @@ my_time_t Field_timestamp::get_timestamp(ulong *sec_part) const int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, const ErrConv *str, - bool was_cut, + int was_cut, bool have_smth_to_conv) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; uint error = 0; my_time_t timestamp; - if (was_cut || !have_smth_to_conv) + if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !have_smth_to_conv) { error= 1; set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1); } + else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut)) + { + error= 3; + set_datetime_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, + str, MYSQL_TIMESTAMP_DATETIME, 1); + } /* Only convert a correct date (not a zero date) */ if (have_smth_to_conv && l_time->month) { @@ -5138,9 +5144,10 @@ int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime, was_cut= MYSQL_TIME_WARN_TRUNCATED; ret= 1; } - else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) && - mysql_type_to_time_type(type()) == MYSQL_TIMESTAMP_DATE && - (ltime->hour || ltime->minute || ltime->second || ltime->second_part)) + else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) && + (MYSQL_TIME_WARN_HAVE_NOTES(was_cut) || + (mysql_type_to_time_type(type()) == MYSQL_TIMESTAMP_DATE && + (ltime->hour || ltime->minute || ltime->second || ltime->second_part)))) { trunc_level= Sql_condition::WARN_LEVEL_NOTE; was_cut|= MYSQL_TIME_WARN_TRUNCATED; @@ -5230,7 +5237,6 @@ int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime, { Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN; int ret= 2; - ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; if (!have_smth_to_conv) @@ -5239,10 +5245,12 @@ int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime, was_cut= MYSQL_TIME_WARN_TRUNCATED; ret= 1; } - else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) && - (ltime->year || ltime->month)) + else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) && + ((ltime->year || ltime->month) || + MYSQL_TIME_WARN_HAVE_NOTES(was_cut))) { - ltime->year= ltime->month= ltime->day= 0; + if (ltime->year || ltime->month) + ltime->year= ltime->month= ltime->day= 0; trunc_level= Sql_condition::WARN_LEVEL_NOTE; was_cut|= MYSQL_TIME_WARN_TRUNCATED; ret= 3; diff --git a/sql/field.h b/sql/field.h index 40be4f7776a..e6a3b9c530b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1543,7 +1543,7 @@ public: class Field_timestamp :public Field_temporal { protected: int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, - bool, bool); + int warnings, bool have_smth_to_conv); public: Field_timestamp(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, diff --git a/sql/item_create.cc b/sql/item_create.cc index 4bd3d4f7e47..3d0a2f58eb7 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5796,6 +5796,13 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } +static bool +have_important_literal_warnings(const MYSQL_TIME_STATUS *status) +{ + return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0; +} + + /** Builder for datetime literals: TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. @@ -5827,13 +5834,15 @@ Item *create_temporal_literal(THD *thd, break; case MYSQL_TYPE_DATETIME: if (!str_to_datetime(cs, str, length, <ime, flags, &status) && - ltime.time_type == MYSQL_TIMESTAMP_DATETIME && !status.warnings) + ltime.time_type == MYSQL_TIMESTAMP_DATETIME && + !have_important_literal_warnings(&status)) item= new (thd->mem_root) Item_datetime_literal(<ime, status.precision); break; case MYSQL_TYPE_TIME: if (!str_to_time(cs, str, length, <ime, 0, &status) && - ltime.time_type == MYSQL_TIMESTAMP_TIME && !status.warnings) + ltime.time_type == MYSQL_TIMESTAMP_TIME && + !have_important_literal_warnings(&status)) item= new (thd->mem_root) Item_time_literal(<ime, status.precision); break; @@ -5842,7 +5851,16 @@ Item *create_temporal_literal(THD *thd, } if (item) + { + if (status.warnings) // e.g. a note on nanosecond truncation + { + ErrConvString err(str, length, cs); + make_truncated_value_warning(current_thd, + Sql_condition::time_warn_level(status.warnings), + &err, ltime.time_type, 0); + } return item; + } if (send_error) { diff --git a/sql/sql_error.h b/sql/sql_error.h index 0a75d7a392d..4c1ebf432c4 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -47,6 +47,16 @@ public: { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; /** + Convert a bitmask consisting of MYSQL_TIME_{NOTE|WARN}_XXX bits + to WARN_LEVEL_XXX + */ + static enum_warning_level time_warn_level(int warnings) + { + return MYSQL_TIME_WARN_HAVE_WARNINGS(warnings) ? + WARN_LEVEL_WARN : WARN_LEVEL_NOTE; + } + + /** Get the MESSAGE_TEXT of this condition. @return the message text. */ diff --git a/sql/sql_time.cc b/sql/sql_time.cc index e2771d0500e..69f92b41ea4 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -311,7 +311,9 @@ str_to_datetime_with_warn(CHARSET_INFO *cs, THD *thd= current_thd; bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status); if (ret_val || status.warnings) - make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, + make_truncated_value_warning(thd, + ret_val ? Sql_condition::WARN_LEVEL_WARN : + Sql_condition::time_warn_level(status.warnings), str, length, flags & TIME_TIME_ONLY ? MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS); DBUG_EXECUTE_IF("str_to_datetime_warn", |