Bug #121573 `IN` with a constant list silently swallows data-conversion errors under strict SQL mode
Submitted: 22 Oct 3:35
Reporter: Chunling Qin Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: DML Severity:S3 (Non-critical)
Version: OS:Any
Assigned to: CPU Architecture:Any

[22 Oct 3:35] Chunling Qin
Description:
MySQL 26.10.0-trunk, commit `561753af986c3c006c4b6c7caa8359748fb55b22`

With strict SQL mode enabled (`STRICT_TRANS_TABLES`, on by default), a data-conversion error raised
while evaluating the left operand of `IN` is **silently swallowed** when the `IN` list is a
**constant list** (the `In_vector_*` fast path). The expression returns `0` with no error.

The semantically equivalent `OR` expansion, which goes through the per-item comparison loop,
**does** raise the error:

```
ERROR 1525 (HY000): Incorrect DATE value: '1'
```

So the same data error is reported or hidden depending only on how the predicate is written.
A systematic type matrix (31 left-operand literals × 14 constant lists = 448 combinations)
reproduced this inconsistency in **84 combinations**.

This matters operationally: `WHERE v IN (DATE'...')` silently classifies rows containing invalid
temporal text as "no match" instead of failing, so data-quality problems go unnoticed, and the
behaviour is unpredictable because rewriting the predicate to an equivalent form suddenly errors out.

How to repeat:
SELECT @@sql_mode LIKE '%STRICT_TRANS_TABLES%' AS strict_on;   -- 1

-- IN (constant list): silent, no error
SELECT '1' IN (DATE'2024-01-01', DATE'2025-01-01') AS in_res;  -- 0   <-- no error raised

-- Equivalent OR expansion: correctly raises the error
SELECT ('1' = DATE'2024-01-01' OR '1' = DATE'2025-01-01') AS or_res;
-- ERROR 1525 (HY000): Incorrect DATE value: '1'
```

Suggested fix:
## Analysis

`Item_func_in::val_int()` only inspects the **boolean** result of `find_item()`:

```cpp
const bool tmp = m_const_array->find_item(args[0]);
null_value = args[0]->null_value || (!tmp && have_null);
return (longlong)(!null_value && tmp != negated);
```

and every `In_vector_*::find_item()` returns `false` on a conversion failure **without propagating
`current_thd->is_error()`**:

```cpp
bool In_vector_date::find_item(Item *item) {
  if (m_used_size == 0) return false;
  Date_val date;
  if (item->val_date(&date, 0)) return false;   // conversion failed -> just returns false
  return std::binary_search(...);
}
```

By contrast, the non-`In_vector` branch of the very same function does check:

```cpp
const int rc = in_item->cmp(args[i]);
if (current_thd->is_error()) return error_int();   // <-- error is propagated here
```

So **only the constant-list fast path** loses the error.