Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1
Description
- MariaDB SYSTEM VERSIONING: `NOT` over a `CASE` comparison drops `TIMESTAMP(6)` precision in `WHERE`
Status: reproduced on MariaDB 13.0.2. Relevant code reviewed on current `main`; current-main runtime was not tested.
-
- Reproduction environment
- MariaDB source: `mariadb-13.0.2`, commit `620a4b5624222048fece7fe1789978ae0675cae2`
- Current `main` reviewed at `9d7ab2c0092df4bc73b64b915464aecf7e5fe6c4`
- Linux x86_64, Clang 14, trace-pc-guard coverage build
-
- Minimal reproducer
```sql
SET time_zone = '+08:00';
CREATE TABLE t (
id INT PRIMARY KEY,
v VARCHAR(8),
valid_from TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
valid_to TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (valid_from, valid_to)
) WITH SYSTEM VERSIONING;
INSERT INTO t(id, v) VALUES (1, 'a'), (2, 'b');
SELECT id, valid_to,
(CASE WHEN TRUE THEN valid_to ELSE valid_to END) <> valid_to AS p,
NOT ((CASE WHEN TRUE THEN valid_to ELSE valid_to END) <> valid_to) AS not_p
FROM t;
SELECT COUNT
FROM t
WHERE NOT ((CASE WHEN TRUE THEN valid_to ELSE valid_to END) <> valid_to);
EXPLAIN EXTENDED
SELECT * FROM t
WHERE NOT ((CASE WHEN TRUE THEN valid_to ELSE valid_to END) <> valid_to);
SHOW WARNINGS;
```
-
- Actual and expected results
Each inserted current row has `valid_to = 2106-02-07 14:28:15.999999`. In projection, `p` is `0` and `not_p` is `1`. Nevertheless, the `WHERE NOT (...)` count is `0`; the expected count is `2`.
Controls using the same predicate with `IS FALSE` or `= 0` both return `2` rows.
-
- EXPLAIN evidence
`SHOW WARNINGS` exposes the rewritten condition as:
```sql
valid_to = TIMESTAMP'2106-02-07 14:28:15.999999'
AND '2106-02-07 14:28:15' = valid_to
```
The injected current-row bound retains `.999999`, while the propagated equality is a seconds-only string literal. The rewritten condition therefore rejects the current rows.
-
- Root cause
`NOT (A <> B)` is normalized during parsing: `negate_expression()` invokes the expression's negation transformer, and `Item_func_ne::negated_item()` constructs equality. That rewrite is valid by itself. The wrong result occurs when optimizer equality/temporal constant propagation interacts with the system-versioned current-row sentinel and the `CASE` expression, producing the seconds-only equality visible in `EXPLAIN`.
Relevant current-main code:
- [`negate_expression()`](https://github.com/MariaDB/server/blob/9d7ab2c0092df4bc73b64b915464aecf7e5fe6c4/sql/sql_parse.cc#L10021-L10055)
- [`Item_func_ne` negation](https://github.com/MariaDB/server/blob/9d7ab2c0092df4bc73b64b915464aecf7e5fe6c4/sql/item_cmpfunc.cc#L6854-L6972)
- [system-versioning condition construction](https://github.com/MariaDB/server/blob/9d7ab2c0092df4bc73b64b915464aecf7e5fe6c4/sql/sql_select.cc#L1043-L1080)
- [temporal max-value handling](https://github.com/MariaDB/server/blob/9d7ab2c0092df4bc73b64b915464aecf7e5fe6c4/sql/field.cc#L5919-L5941)
The minimized reproducer contains no GIS expression or `NULLIF`; this is unrelated to the `ST_IsValid(NULL)` predicate issue.
-
- Impact
A read-only `SELECT` can silently omit valid current rows when a negated comparison over a `CASE` expression references a system-versioned `TIMESTAMP(6)` period end. Projection and filtering disagree. No write corruption has been demonstrated.
-
- Duplicate audit
No exact public duplicate was found for the combination of the system-versioned `TIMESTAMP(6)` row-end sentinel, negated comparison, and precision-losing equality propagation. MDEV-36440 is related to `NOT NOT`/`WHERE` mismatches but does not contain this temporal sentinel or precision-propagation trigger. MDEV-8766 and MDEV-8706 are prior temporal `Item_equal` propagation bugs with different reproducers.
-
- Discovery
Found by DBMS-StateFuzz while exercising typed, compositional MariaDB queries and three-valued-logic partitioning.
Credit: Zheng Wang, Yanjie Zhao, and Yiyang Liu.
Attachments
Issue Links
- relates to
-
MDEV-39384 Wrong result when selecting from precise-versioned table
-
- Stalled
-