[MDEV-30471] Inconsistent casting of invalid datetime values Created: 2023-01-25  Updated: 2023-01-31

Status: Open
Project: MariaDB Server
Component/s: None
Affects Version/s: 10.2.24, 10.8.3
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Andrei Lurie Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Observing inconsistent behavior when casting invalid datetime values (when zero dates are allowed).
For example:

set sql_mode = '';
create table t1(vc varchar(10), d date);
insert into t1 values('abc', 'abc');
insert into t1 values('0000-00-00', '0000-00-00');
insert into t1 values('123', cast('123' as date));
insert into t1 values('456', '456');
insert into t1 values(null, null);
select * from t1;
+------------+------------+
| vc         | d          |
+------------+------------+
| abc        | 0000-00-00 |
| 0000-00-00 | 0000-00-00 |
| 123        | NULL       |   --> so result of the explicit cast was NULL
| 456        | 0000-00-00 | --> but result of implicit/assignment cast was zero date
| NULL       | NULL       |
+------------+------------+

The result of the explicit cast being NULL makes sense, e.g.

select cast('abc' as date);
+---------------------+
| cast('abc' as date) |
+---------------------+
| NULL                |
+---------------------+

What follows is confusing/inconsistent:

 select d, vc, cast(vc as date) from t1 where d = cast(vc as date);
+------------+------------+------------------+
| d          | vc         | cast(vc as date) |
+------------+------------+------------------+
| 0000-00-00 | abc        | NULL             |
| 0000-00-00 | 0000-00-00 | 0000-00-00       |
| 0000-00-00 | 456        | NULL             |
+------------+------------+------------------+

It looks as if the explicit cast result is zero when under predicate context and is NULL when under the projection context. Except:

select d, vc, cast(vc as date) from t1 where d = cast(vc as date) and cast(vc as date) is null;
+------------+------+------------------+
| d          | vc   | cast(vc as date) |
+------------+------+------------------+
| 0000-00-00 | abc  | NULL             |
| 0000-00-00 | 456  | NULL             |
+------------+------+------------------+

So, the "d = cast(vc as date)" term acts as if result of the cast was '0000-00-00' but the "cast(vc as date) is null" term acts as if result of the cast was NULL.

Could someone please shed some light on this?
Most important is what is the intended semantics of converting invalid values to datetime (date, time, datetime, timestamp) when zero dates are allowed? Is the result a NULL value or a zero?



 Comments   
Comment by Andrei Lurie [ 2023-01-31 ]

The reason for this behavior is that Type_handler::Item_send_datetime uses default datetime Options:
item->get_date(protocol->thd, &buf->value.m_time, Datetime::Options(protocol->thd));
And for comparison, and cast, it is also using "FUZZY" option, e.g.:
Options(default_flags_for_get_date() | (mode & TIME_FUZZY_DATES), and
static date_conv_mode_t comparison_flags_for_get_date() ... return TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES;

This leads to make_fuzzy_date() to set the type to MYSQL_TIMESTAMP_NONE (will lead to NULL) in one case and MYSQL_TIMESTAMP_DATETIME (will lead to 0000-00-00) in another.

This explains the fuzzy behavior where the same CAST in comparison returns 0000-00-00 but returns NULL when returning data or processing IS NULL predicate.

Would a less confusing behavior be to also return 0000-00-00 when sending data, i.e. adding TIME_FUZZY_DATES to the Type_handler::Item_send_datetime?

Generated at Thu Feb 08 10:16:29 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.