Skip to content

fix: MySQL comprehensions generated SQL that silently matched nothing - #27

Merged
richardwooding merged 1 commit into
mainfrom
fix/mysql-comprehensions
Aug 22, 2026
Merged

fix: MySQL comprehensions generated SQL that silently matched nothing#27
richardwooding merged 1 commit into
mainfrom
fix/mysql-comprehensions

Conversation

@richardwooding

Copy link
Copy Markdown
Contributor

Ports SPANDigital/cel2sql#177 and the MySQL half of SPANDigital/cel2sql#169, matching SPANDigital/cel2sql4j#44.

The bugs

MySQL used the default comprehension source — JSON_TABLE(...) AS x — where a bare reference to x is an unknown column (JSON_TABLE is table-valued). The integration catalog skipped every MySQL comprehension case ("comprehension" => dialect.Name != DialectName.MySql) instead of fixing it.

Fixing the reference alone isn't enough: the MySQL 8.x optimizer transforms a correlated EXISTS into a semijoin and loses the correlation to the JSON_TABLE source, so exists()/all() execute without error and silently match nothing (works from 9.x; verified against 8.4.11 and 9.7.1 locally).

The fix

  • MySqlDialect.WriteComprehensionSource(SELECT value AS x FROM JSON_TABLE(...) AS jt) AS _t, the derived-table idiom SqliteDialect already uses
  • New IDialect.WriteComprehensionExists/WriteComprehensionNotExists (defaults in DialectBase) with MySQL emitting (SELECT COUNT(*) FROM ...) > 0 / = 0
  • MySQL comprehension skip removed from the integration catalogcomp_all/comp_exists/comp_exists_one now execute against the MySQL container in CI
  • Unit expectations added for all five macros on MySQL

Other dialects' output is unchanged. Same fix shipped in Go (cel2sql v3.8.10) and Python (pycel2sql v0.4.2); Java is in SPANDigital/cel2sql4j#44.

Ports SPANDigital/cel2sql#177 (and the MySQL half of #169), matching
the fix in cel2sql4j. MySQL used the default comprehension source,
JSON_TABLE(...) AS x, where a bare reference to x is an unknown
column — and the integration catalog skipped every MySQL comprehension
case instead of fixing it. Beyond that, the MySQL 8.x optimizer
transforms a correlated EXISTS into a semijoin and loses the
correlation to JSON_TABLE, so exists()/all() executed without error
and matched nothing (works from 9.x; verified against MySQL 8.4.11
and 9.7.1).

- MySqlDialect.WriteComprehensionSource renames the value column to
  the iteration variable through a derived table, the same idiom
  SqliteDialect already uses for json_each
- New IDialect.WriteComprehensionExists/WriteComprehensionNotExists
  default to EXISTS/NOT EXISTS; MySQL emits COUNT comparisons
- The MySQL comprehension skip is removed from the integration
  catalog, so comp_all/comp_exists/comp_exists_one now execute
  against the MySQL container in CI
- Unit expectations added for all five macros on MySQL
@richardwooding
richardwooding merged commit ddc44d2 into main Aug 22, 2026
2 checks passed
@richardwooding
richardwooding deleted the fix/mysql-comprehensions branch August 22, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant