Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 12.3.2
Description
MariaDB returns different values and result metadata for two relationally
equivalent `UNION` queries. The query has three branches:
1. An empty branch whose expression type is `TIME`.
2. A branch returning one `DATE` value.
3. An empty integer branch.
When all expressions appear directly in the `UNION`, MariaDB returns the date as
`2026-05-21`. When only the empty `TIME` branch is put behind a CTE, derived
table, or temporary-table boundary, MariaDB returns
`2026-05-21 00:00:00` instead.
The empty branches return no rows in either query, but their expression types
still participate in `UNION` type negotiation. Moving an empty branch across a
relational boundary should not change the value produced by another branch.
- How to repeat
No base tables or test data are required. Select an isolated database so that
the temporary-table variant can also be executed:
|
|
```sql
|
DROP DATABASE IF EXISTS date_union_type_test;
|
CREATE DATABASE date_union_type_test;
|
USE date_union_type_test;
|
```
|
|
Run the direct query:
|
|
```sql
|
(SELECT CAST('01:02:03' AS TIME) AS d WHERE FALSE) |
UNION
|
(SELECT CAST('2026-05-21' AS DATE)) |
UNION ALL
|
SELECT 1 WHERE FALSE; |
```
|
|
Result:
|
|
```text
|
2026-05-21 |
```
|
|
Now place only the empty `TIME` branch in a CTE:
|
|
```sql
|
WITH time_cut AS (
|
SELECT CAST('01:02:03' AS TIME) AS d |
WHERE FALSE
|
)
|
(SELECT d FROM time_cut
|
UNION
|
SELECT CAST('2026-05-21' AS DATE)) |
UNION ALL
|
SELECT 1 WHERE FALSE; |
```
|
|
Result:
|
|
```text
|
2026-05-21 00:00:00 |
```
|
|
The derived-table form produces the same changed result:
|
|
```sql
|
(SELECT d
|
FROM (
|
SELECT CAST('01:02:03' AS TIME) AS d |
WHERE FALSE
|
) AS time_cut
|
UNION
|
SELECT CAST('2026-05-21' AS DATE)) |
UNION ALL
|
SELECT 1 WHERE FALSE; |
```
|
|
The temporary-table form also produces the changed result:
|
|
```sql
|
CREATE TEMPORARY TABLE time_cut AS
|
SELECT CAST('01:02:03' AS TIME) AS d |
WHERE FALSE;
|
|
|
(SELECT d FROM time_cut
|
UNION
|
SELECT CAST('2026-05-21' AS DATE)) |
UNION ALL
|
SELECT 1 WHERE FALSE; |
```
|
|
- Metadata verification
With PyMySQL, the direct and rewritten queries both expose a string result, but
their declared maximum lengths differ:
|
|
```text
|
Direct query: MYSQL_TYPE_VAR_STRING, length 40 |
CTE/derived query: MYSQL_TYPE_VAR_STRING, length 76 |
```
|
|
The length change corresponds to MariaDB formatting the `DATE` branch as a
date-only string in the direct query and as a full `DATETIME` string after the
boundary.
- Expected result
All equivalent forms should return the same value and compatible metadata. The
empty `TIME` branch contains no rows, and moving it into a CTE, derived table, or
temporary table does not change the relational result.
```text
|
2026-05-21 |
```
|
|
- Actual result
The direct query returns:
|
|
```text
|
2026-05-21 |
```
|
|
The CTE, derived-table, and temporary-table forms return:
```text
|
2026-05-21 00:00:00 |
```
|