Bug #119670 Incorrect result caused by index
Submitted: 13 Jan 13:46 Modified: 13 Jan 14:36
Reporter: chi zhang Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S1 (Critical)
Version:8.0.44 OS:Any
Assigned to: CPU Architecture:Any

[13 Jan 13:46] chi zhang
Description:
Hi,

In the following test case, there are two equivalent queries: one is a normal SELECT, and anothe is a prepared statement. However, they have different results: the normal SELECT returns one row, which is unexpected; and the prepared statement returns empty result. If I delete the index, the normal SELECT will have correct result.

```
CREATE TABLE t2(c0 TINYINT(168));
CREATE INDEX i0 ON t2(c0 DESC);
REPLACE INTO t2(c0) VALUES(0);
SELECT c0 FROM t2 WHERE (NOT (((t2.c0) NOT IN (CAST(0.2914388740243027 AS DOUBLE))) || (t2.c0))); -- 0
SET @a = 0.2914388740243027;
PREPARE prepare_query FROM 'SELECT c0 FROM t2 WHERE (NOT (((t2.c0) NOT IN (CAST(? AS DOUBLE))) || (t2.c0)))';
EXECUTE prepare_query USING @a; -- empty result
DEALLOCATE PREPARE prepare_query;
```

This is the query plan of the normal query:
```
EXPLAIN
-> Filter: (t2.c0 = 0)  (cost=0.35 rows=1)\n    -> Covering index lookup on t2 using i0 (c0 = cast(0.2914388740243027 as double))  (cost=0.35 rows=1)\n
```

This is the query plan of the prepared statement:
```
EXPLAIN
-> Filter: (t2.c0 = <cache>(cast(0.2914388740243027 as double)))  (cost=0.35 rows=1)\n    -> Covering index lookup on t2 using i0 (c0 = 0)  (cost=0.35 rows=1)\n
```

How to repeat:
```
CREATE TABLE t2(c0 TINYINT(168));
CREATE INDEX i0 ON t2(c0 DESC);
REPLACE INTO t2(c0) VALUES(0);
SELECT c0 FROM t2 WHERE (NOT (((t2.c0) NOT IN (CAST(0.2914388740243027 AS DOUBLE))) || (t2.c0))); -- 0
SET @a = 0.2914388740243027;
PREPARE prepare_query FROM 'SELECT c0 FROM t2 WHERE (NOT (((t2.c0) NOT IN (CAST(? AS DOUBLE))) || (t2.c0)))';
EXECUTE prepare_query USING @a; -- empty result
DEALLOCATE PREPARE prepare_query;
```
[13 Jan 14:36] Roy Lyseng
Thank you for the bug report.
Verified as described.