From f5d7229762e3c0e4cf98f223b41cb6d381a767bf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Dec 2003 20:25:45 +0300 Subject: [PATCH] Fix for Bug #1448 "Date parsing fails, and fails to complain about it". Now numbers representing illegal timestamps are converted to 0 value if they are stored as timestamp or datetime. This behaviour is consistent with manual and with behaviour of string -> timestamp conversion. mysql-test/r/type_datetime.result: Added test if ranges are checked during integer, string -> timestamp conversion mysql-test/r/type_timestamp.result: Added test if ranges are checked during integer, string -> datetime conversion mysql-test/t/type_datetime.test: Added test if ranges are checked during integer, string -> datetime conversion mysql-test/t/type_timestamp.test: Added test if ranges are checked during integer, string -> timestamp conversion sql/field.cc: Checks of month, day, hour, minute and second ranges were added to storing of integer into Field_datetime and Field_timestamp and so for integer -> datetime, timestamp conversion. --- mysql-test/r/type_datetime.result | 15 ++++++- mysql-test/r/type_timestamp.result | 20 ++++++++- mysql-test/t/type_datetime.test | 5 ++- mysql-test/t/type_timestamp.test | 7 ++- sql/field.cc | 70 +++++++++++++++++++++--------- 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 5df4f355cfb..756deab80e0 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -1,6 +1,6 @@ drop table if exists t1; create table t1 (t datetime); -insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959); +insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); select * from t1; t 2000-01-01 00:00:00 @@ -15,6 +15,11 @@ t 1999-12-31 23:59:59 1000-01-01 00:00:00 9999-12-31 23:59:59 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 delete from t1 where t > 0; optimize table t1; Table Op Msg_type Msg_text @@ -22,7 +27,8 @@ test.t1 optimize status OK check table t1; Table Op Msg_type Msg_text test.t1 check status OK -insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"); +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); select * from t1; t 2000-01-01 00:00:00 @@ -38,6 +44,11 @@ t 1999-12-31 23:59:59 1000-01-01 00:00:00 9999-12-31 23:59:59 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 3d5d74709c1..9403b73d459 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -43,7 +43,7 @@ date_format(a,"%Y %y") year(a) year(now()) 1970 70 1970 1970 drop table t1; create table t1 (ix timestamp); -insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101); select * from t1; ix 19991101000000 @@ -55,6 +55,24 @@ ix 19990501000000 19991101000000 19990501000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +delete from t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"); +select * from t1; +ix +19991101000000 +19990102030405 +19990630232922 +19990601000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 drop table t1; CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); INSERT INTO t1 VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959); diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 51b65d00243..850e5238111 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -4,12 +4,13 @@ drop table if exists t1; create table t1 (t datetime); -insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959); +insert into t1 values(101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); select * from t1; delete from t1 where t > 0; optimize table t1; check table t1; -insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"); +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); select * from t1; drop table t1; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index eb0def74a17..0c88f1b8025 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -34,8 +34,11 @@ select date_format(a,"%Y %y"),year(a),year(now()) from t1; drop table t1; create table t1 (ix timestamp); -insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); -select * from t1; +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101); +select * from t1; +delete from t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"); +select * from t1; drop table t1; CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); diff --git a/sql/field.cc b/sql/field.cc index 43481ca0963..259314cb4db 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2520,31 +2520,59 @@ void Field_timestamp::store(double nr) ** function. */ -static longlong fix_datetime(longlong nr) +static longlong fix_datetime(longlong nr, TIME *time_res) { + long part1,part2; + if (nr == LL(0) || nr >= LL(10000101000000)) - return nr; // Normal datetime >= Year 1000 + goto ok; if (nr < 101) goto err; if (nr <= (YY_PART_YEAR-1)*10000L+1231L) - return (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069 + { + nr= (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069 + goto ok; + } if (nr < (YY_PART_YEAR)*10000L+101L) goto err; if (nr <= 991231L) - return (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999 + { + nr= (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999 + goto ok; + } if (nr < 10000101L) goto err; if (nr <= 99991231L) - return nr*1000000L; + { + nr= nr*1000000L; + goto ok; + } if (nr < 101000000L) goto err; if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959)) - return nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069 + { + nr= nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069 + goto ok; + } if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000)) goto err; if (nr <= LL(991231235959)) - return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999 + nr= nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999 + ok: + part1=(long) (nr/LL(1000000)); + part2=(long) (nr - (longlong) part1*LL(1000000)); + time_res->year= (int) (part1/10000L); part1%=10000L; + time_res->month= (int) part1 / 100; + time_res->day= (int) part1 % 100; + time_res->hour= (int) (part2/10000L); part2%=10000L; + time_res->minute=(int) part2 / 100; + time_res->second=(int) part2 % 100; + + if (time_res->month <= 12 && time_res->day <= 31 && time_res->hour <= 23 && + time_res->minute <= 59 && time_res->second <= 59) + return nr; + err: current_thd->cuted_fields++; return LL(0); @@ -2555,20 +2583,18 @@ void Field_timestamp::store(longlong nr) { TIME l_time; time_t timestamp; - long part1,part2; - if ((nr=fix_datetime(nr))) + if ((nr=fix_datetime(nr, &l_time))) { long not_used; - part1=(long) (nr/LL(1000000)); - part2=(long) (nr - (longlong) part1*LL(1000000)); - l_time.year= (int) (part1/10000L); part1%=10000L; - l_time.month= (int) part1 / 100; - l_time.day= (int) part1 % 100; - l_time.hour= (int) (part2/10000L); part2%=10000L; - l_time.minute=(int) part2 / 100; - l_time.second=(int) part2 % 100; - timestamp=my_gmt_sec(&l_time, ¬_used); + + if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) + { + current_thd->cuted_fields++; + timestamp=0; + } + else + timestamp=my_gmt_sec(&l_time, ¬_used); } else timestamp=0; @@ -3406,13 +3432,15 @@ void Field_datetime::store(double nr) void Field_datetime::store(longlong nr) { - if (nr < 0 || nr > LL(99991231235959)) + TIME l_time; + + nr=fix_datetime(nr, &l_time); + + if (l_time.year > 9999) { nr=0; current_thd->cuted_fields++; } - else - nr=fix_datetime(nr); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) {