Details
Description
Zero datetime reinterprets as '1970-01-01 00:00:00' on field_datetime=field_timestamp
SET sql_mode=''; |
SET time_zone='+00:00'; |
CREATE OR REPLACE TABLE t1 (a TIMESTAMP); |
INSERT INTO t1 VALUES ('0000-00-00 00:00:00'); |
SELECT * FROM t1; |
+---------------------+
|
| a |
|
+---------------------+
|
| 0000-00-00 00:00:00 |
|
+---------------------+
|
CREATE OR REPLACE TABLE t2 (a datetime); |
INSERT INTO t2 SELECT a FROM t1; |
SELECT * FROM t2; |
+---------------------+
|
| a |
|
+---------------------+
|
| 1970-01-01 00:00:00 |
|
+---------------------+
|
Looks wrong. The zero datetime was erroneously re-interpreted as '1970-01-01 00:00:00'.
Note, if I wrap the column t2.a into COALESCE(), it works OK:
INSERT INTO t2 SELECT COALESCE(a) FROM t1; |
SELECT * FROM t2; |
+---------------------+
|
| a |
|
+---------------------+
|
| 1970-01-01 00:00:00 |
|
| 0000-00-00 00:00:00 |
|
+---------------------+
|
The problem resides in this code:
int Field_timestamp::save_in_field(Field *to) |
{
|
ulong sec_part;
|
my_time_t ts= get_timestamp(&sec_part);
|
return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); |
}
|
It should not call store_timestamp_dec() for zero datetime, as this method knows nothing about zero datetime. It can store only real timestamp values.
A proposed fix:
int Field_timestamp::save_in_field(Field *to) |
{
|
ulong sec_part;
|
my_time_t ts= get_timestamp(&sec_part);
|
if (!ts && ! sec_part) |
return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); |
return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); |
}
|
Attachments
Issue Links
- relates to
-
MDEV-34037 DATETIME <-> TIMESTAMP conversion in a virtual column corrups the table on @@time_zone change
-
- In Review
-
-
MDEV-34061 unix_timestamp(coalesce(timestamp_column)) returns NULL on '1970-01-01 00:00:00.000001'
-
- Closed
-
-
MDEV-34088 The TIMESTAMP value of '1970-01-01 00:00:00' can be indirectly inserted in strict mode
-
- Closed
-
Activity
Field | Original Value | New Value |
---|---|---|
Link |
This issue relates to |
Link | This issue relates to MDEV-34037 [ MDEV-34037 ] |
Description |
Zero datetime reinterprets as '1970-01-01 00:00:00' on field_datetime=field_timestamp
{code:sql} SET sql_mode=DEFAULT; SET time_zone='+00:00'; CREATE OR REPLACE TABLE t1 (a TIMESTAMP); INSERT INTO t1 VALUES (0); SELECT * FROM t1; {code} {noformat} +---------------------+ | a | +---------------------+ | 0000-00-00 00:00:00 | +---------------------+ {noformat} {code:sql} CREATE OR REPLACE TABLE t2 (a datetime); INSERT INTO t2 SELECT a FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | +---------------------+ {noformat} Looks wrong. The zero datetime was erroneously re-interpreted as '1970-01-01 00:00:00'. Note, if I wrap the column t2.a into COALESCE(), it works OK: {code:sql} INSERT INTO t2 SELECT COALESCE(a) FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | | 0000-00-00 00:00:00 | +---------------------+ {noformat} The problem resides in this code: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} It should not call store_timestamp_dec() for zero datetime, as this method knows nothing about zero datetime. It can store only real timestamp values. A proposed fix: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); if (!ts && ! sec_part) return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} |
Zero datetime reinterprets as '1970-01-01 00:00:00' on field_datetime=field_timestamp
{code:sql} SET sql_mode=''; SET time_zone='+00:00'; CREATE OR REPLACE TABLE t1 (a TIMESTAMP); INSERT INTO t1 VALUES (0); SELECT * FROM t1; {code} {noformat} +---------------------+ | a | +---------------------+ | 0000-00-00 00:00:00 | +---------------------+ {noformat} {code:sql} CREATE OR REPLACE TABLE t2 (a datetime); INSERT INTO t2 SELECT a FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | +---------------------+ {noformat} Looks wrong. The zero datetime was erroneously re-interpreted as '1970-01-01 00:00:00'. Note, if I wrap the column t2.a into COALESCE(), it works OK: {code:sql} INSERT INTO t2 SELECT COALESCE(a) FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | | 0000-00-00 00:00:00 | +---------------------+ {noformat} The problem resides in this code: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} It should not call store_timestamp_dec() for zero datetime, as this method knows nothing about zero datetime. It can store only real timestamp values. A proposed fix: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); if (!ts && ! sec_part) return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} |
Description |
Zero datetime reinterprets as '1970-01-01 00:00:00' on field_datetime=field_timestamp
{code:sql} SET sql_mode=''; SET time_zone='+00:00'; CREATE OR REPLACE TABLE t1 (a TIMESTAMP); INSERT INTO t1 VALUES (0); SELECT * FROM t1; {code} {noformat} +---------------------+ | a | +---------------------+ | 0000-00-00 00:00:00 | +---------------------+ {noformat} {code:sql} CREATE OR REPLACE TABLE t2 (a datetime); INSERT INTO t2 SELECT a FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | +---------------------+ {noformat} Looks wrong. The zero datetime was erroneously re-interpreted as '1970-01-01 00:00:00'. Note, if I wrap the column t2.a into COALESCE(), it works OK: {code:sql} INSERT INTO t2 SELECT COALESCE(a) FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | | 0000-00-00 00:00:00 | +---------------------+ {noformat} The problem resides in this code: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} It should not call store_timestamp_dec() for zero datetime, as this method knows nothing about zero datetime. It can store only real timestamp values. A proposed fix: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); if (!ts && ! sec_part) return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} |
Zero datetime reinterprets as '1970-01-01 00:00:00' on field_datetime=field_timestamp
{code:sql} SET sql_mode=''; SET time_zone='+00:00'; CREATE OR REPLACE TABLE t1 (a TIMESTAMP); INSERT INTO t1 VALUES ('0000-00-00 00:00:00'); SELECT * FROM t1; {code} {noformat} +---------------------+ | a | +---------------------+ | 0000-00-00 00:00:00 | +---------------------+ {noformat} {code:sql} CREATE OR REPLACE TABLE t2 (a datetime); INSERT INTO t2 SELECT a FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | +---------------------+ {noformat} Looks wrong. The zero datetime was erroneously re-interpreted as '1970-01-01 00:00:00'. Note, if I wrap the column t2.a into COALESCE(), it works OK: {code:sql} INSERT INTO t2 SELECT COALESCE(a) FROM t1; SELECT * FROM t2; {code} {noformat} +---------------------+ | a | +---------------------+ | 1970-01-01 00:00:00 | | 0000-00-00 00:00:00 | +---------------------+ {noformat} The problem resides in this code: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} It should not call store_timestamp_dec() for zero datetime, as this method knows nothing about zero datetime. It can store only real timestamp values. A proposed fix: {code:cpp} int Field_timestamp::save_in_field(Field *to) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); if (!ts && ! sec_part) return to->store_time_dec(Datetime::zero().get_mysql_time(), decimals()); return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } {code} |
issue.field.resolutiondate | 2024-05-04 19:31:42.0 | 2024-05-04 19:31:42.397 |
Fix Version/s | 10.5.25 [ 29626 ] | |
Fix Version/s | 10.6.18 [ 29627 ] | |
Fix Version/s | 10.11.8 [ 29630 ] | |
Fix Version/s | 11.1.5 [ 29629 ] | |
Fix Version/s | 11.2.4 [ 29631 ] | |
Fix Version/s | 11.4.2 [ 29633 ] | |
Fix Version/s | 11.5.1 [ 29634 ] | |
Fix Version/s | 11.3.2 [ 29522 ] | |
Fix Version/s | 11.0.1 [ 28548 ] | |
Fix Version/s | 10.5 [ 23123 ] | |
Resolution | Fixed [ 1 ] | |
Status | Open [ 1 ] | Closed [ 6 ] |
Link |
This issue relates to |
Fix Version/s | 11.0.6 [ 29628 ] | |
Fix Version/s | 11.0.1 [ 28548 ] |