Bug #121480 Wrong result with subquery materialization: lookup on <auto_distinct_key> converts the probe value to the key type
Submitted: 11 Oct 15:44 Modified: 15 Oct 9:34
Reporter: Ann Calla Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:8.0.46, 8.4.11, 9.7.2, 26.07 OS:Ubuntu (24.04)
Assigned to: CPU Architecture:x86 (x86_64)

[11 Oct 15:44] Ann Calla
Description:
When an IN / EXISTS subquery is materialized and probed through its automatic key, the outer value appears to be converted to the type of the materialized column before the lookup.

(1) A DOUBLE probing a DECIMAL key misses. 18446744073709551616 (2^64) is stored exactly in a DOUBLE column and compares equal to the literal 18446744073709551617 (comparison as DOUBLE, "c = 18446744073709551617" returns 1). With the subquery materialized, IN returns nothing and NOT IN returns the row.

(2) A FLOAT probing an integer key matches falsely. No hint is needed for the second test case: the predicate is false or NULL for every pair of rows, yet EXISTS returns the row 0.92976. With optimizer_switch='materialization=off' the result is correct.

How to repeat:
-- (1) false miss
CREATE TABLE d(c DOUBLE);
CREATE TABLE o(x INT);
INSERT INTO d VALUES (18446744073709551616);
INSERT INTO o VALUES (1);

SELECT c = 18446744073709551617 FROM d;                                   -- 1
SELECT c FROM d WHERE c IN (SELECT 18446744073709551617 FROM o);          -- 1 row (correct)
SELECT c FROM d WHERE c IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ 18446744073709551617 FROM o);
-- expected: 1.8446744073709552e19
-- actual:   empty
SELECT c FROM d WHERE c NOT IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ 18446744073709551617 FROM o);
-- expected: empty
-- actual:   1.8446744073709552e19

-- (2) false match, default settings, no hint
CREATE TABLE a(c0 MEDIUMINT);
INSERT INTO a VALUES (0),(10),(NULL),(NULL),(-8388608),(0),(8388607);
CREATE TABLE b(c0 FLOAT, c1 DECIMAL);
INSERT INTO b(c1, c0) VALUES (-74, 1842012469),(10, 15.0);
INSERT INTO b(c0) VALUES (0.9297596312699918);
INSERT INTO b(c1) VALUES (-2059671427);

SELECT a.c0, b.c0 FROM a, b WHERE (NOT (a.c0 < 0.020188831473858193)) IN (b.c0);
-- empty: the predicate is never true

SELECT b.c0 FROM b WHERE EXISTS (SELECT 1 FROM a WHERE (NOT (a.c0 < 0.020188831473858193)) IN (b.c0));
-- expected: empty
-- actual:   0.92976

SET optimizer_switch='materialization=off';
SELECT b.c0 FROM b WHERE EXISTS (SELECT 1 FROM a WHERE (NOT (a.c0 < 0.020188831473858193)) IN (b.c0));
-- empty (correct)
[15 Oct 9:34] Chaithra Marsur Gopala Reddy
Hi Ann Calla,

Thank you for the test case Verified as described.