Skip to content

Conversation

@Olernov
Copy link
Contributor

@Olernov Olernov commented Jan 16, 2026

When evaluating (SELECT NULL, NULL) IN (SELECT 1, 2 FROM t), the result was incorrectly 0 instead of NULL.

The IN-to-EXISTS transformation wraps comparison predicates with trigcond() guards:

WHERE trigcond(NULL = 1) AND trigcond(NULL = 2)

During optimization, make_join_select() extracted this as a "constant condition" (used_tables() = 0) and evaluated it. With guards ON, the condition evaluated to FALSE (NULL treated as FALSE), triggering "Impossible WHERE". At runtime, guards would be turned OFF for NULL columns, but the optimizer had already marked the subquery as returning no rows.

Fix: Override used_tables() in Item_func_trig_cond to include RAND_TABLE_BIT. This prevents trigcond() from being extracted as a constant condition, deferring evaluation to runtime when guards have correct values.

When evaluating (SELECT NULL, NULL) IN (SELECT 1, 2 FROM t), the result
was incorrectly 0 instead of NULL.

The IN-to-EXISTS transformation wraps comparison predicates with
trigcond() guards:

  WHERE trigcond(NULL = 1) AND trigcond(NULL = 2)

During optimization, make_join_select() extracted this as a "constant
condition" (used_tables() = 0) and evaluated it. With guards ON, the
condition evaluated to FALSE (NULL treated as FALSE), triggering
"Impossible WHERE". At runtime, guards would be turned OFF for NULL
columns, but the optimizer had already marked the subquery as returning
no rows.

Fix: Override used_tables() in Item_func_trig_cond to include
RAND_TABLE_BIT. This prevents trigcond() from being extracted as a
constant condition, deferring evaluation to runtime when guards have
correct values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants