Bug #107495 Prepared statements with the union operator and null timestamps return an error
Submitted: 6 Jun 2022 23:13 Modified: 8 Jun 2022 21:55
Reporter: Duncan Cowan Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Prepared statements Severity:S2 (Serious)
Version:8.0.29 OS:Linux (Docker)
Assigned to: CPU Architecture:Any
Tags: regression

[6 Jun 2022 23:13] Duncan Cowan
Description:
When executing a prepared select statement which uses the 'union' operator in a subquery, if the table contains a nullable timestamp and an outer 'where' condition on a timestamp or datetime field, the following error is returned:

Incorrect TIMESTAMP value: ''

On version 8.0.28 the same query with the same bindings worked fine and would successfully return the expected result, but upgrading to 8.0.29 breaks it. This means upgrading to the latest version can suddenly cause unexpected errors in production environments.

How to repeat:
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.29    |
+-----------+
1 row in set (0.00 sec)

mysql> create database example;
Query OK, 1 row affected (0.00 sec)

mysql> use example;
Database changed
mysql> CREATE TABLE test_data( id BIGINT AUTO_INCREMENT, name VARCHAR(256), created_at timestamp NULL DEFAULT NULL, CONSTRAINT PRIMARY KEY (id) );
Query OK, 0 rows affected (0.02 sec)

mysql> PREPARE example FROM '
    '> select `a`.*
    '>         from (
    '>             (select * from `test_data` where `id` = ?)
    '>             union
    '>             (select * from `test_data` where `name` = ?)
    '>         ) as `a`
    '>         where (`created_at` >= ?)
    '> ';
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> SET @a = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @b = 2;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @c = '2022-05-05 12:00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> EXECUTE example USING @a, @b, @c;
ERROR 1525 (HY000): Incorrect TIMESTAMP value: ''

-------------------------------------------------------

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.28    |
+-----------+
1 row in set (0.00 sec)

mysql> create database example;
Query OK, 1 row affected (0.00 sec)

mysql> use example;
Database changed
mysql> CREATE TABLE test_data( id BIGINT AUTO_INCREMENT, name VARCHAR(256), created_at timestamp NULL DEFAULT NULL, CONSTRAINT PRIMARY KEY (id) );
Query OK, 0 rows affected (0.02 sec)

mysql> PREPARE example FROM '
    '> select `a`.*
    '>         from (
    '>             (select * from `test_data` where `id` = ?)
    '>             union
    '>             (select * from `test_data` where `name` = ?)
    '>         ) as `a`
    '>         where (`created_at` >= ?)
    '> ';
Query OK, 0 rows affected (0.01 sec)
Statement prepared

mysql> SET @a = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @b = 2;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @c = '2022-05-05 12:00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> EXECUTE example USING @a, @b, @c;
Empty set (0.00 sec)

-------------------------------------------------------

Note: I have, of course, massively simplified the example to the point where it's a completely pointless query! But in much more complicated queries the problem persists.

Suggested fix:
It appears it begins working again if the outer 'where' condition is applied to the unioned subqueries individually. However, this can take quite a lot of work depending on the complexity of the query.
[7 Jun 2022 9:00] MySQL Verification Team
Hello Duncan Cowan,

Thank you for the report and test case.
Verified as described.

regards,
Umesh
[8 Jun 2022 6:37] Roy Lyseng
Posted by developer:
 
This is duplicate of bug#34148712, fixed in 8.0.30.

Possible workaround:

  set optimizer_switch='derived_condition_pushdown=off';
[8 Jun 2022 8:35] MySQL Verification Team
This is duplicate of Bug #107230, please see Bug #107230.

Dev's suggested possible workaround:
set optimizer_switch='derived_condition_pushdown=off';
[8 Jun 2022 21:55] Duncan Cowan
Thanks! Sorry for missing the existing bug entry.