Found 2026-09-04 while specifying Epic 21 (Core SQL Front Door), by running the real app.softnetwork.elastic.sql.parser.Parser compiled from main (ac54a079).
Measured — all reject
REJECT string matching regex (?i)(binary|var… | SELECT CAST(amount AS SIGNED) FROM t
REJECT string matching regex (?i)(binary|var… | SELECT CAST(amount AS UNSIGNED) FROM t
REJECT string matching regex (?i)(binary|var… | SELECT CAST(amount AS NUMERIC) FROM t
REJECT string matching regex (?i)(binary|var… | SELECT CAST(name AS TEXT) FROM t
REJECT ) expected but ( found | SELECT CAST(amount AS DECIMAL(10,2)) FROM t
REJECT ) expected but ( found | SELECT CAST(name AS CHAR(10)) FROM t
REJECT end of input expected | SELECT CONVERT(name USING utf8) FROM t
The failing production is the target-type regex, not the operand.
Why it matters
CAST(x AS SIGNED) / AS UNSIGNED is what Tableau's MySQL dialect generates — the dialect Epic 19 captured 89 of its 94 corpus rejections from. Parameterised types (DECIMAL(p,s), CHAR(n)) and the alias names (NUMERIC, TEXT) are standard across MySQL / PostgreSQL / SQL-92 generators.
Note — this supersedes a false filing
#267 claimed the operand surface rejected bare literals (CAST('125' AS BIGINT)). That is false and was refuted by measurement — all four spellings accept literals today. The operand surface was never the gap; this one is. #267 is being closed as not-reproducible; this issue is not a re-purposing of that number.
Scope
The conversion target-type production in sql/src/main/scala/app/softnetwork/elastic/sql/parser/. Each accepted type needs an explicit ES-type mapping decision — an alias that silently resolves to the wrong numeric type, or a parameterised precision that looks honoured but is ignored, is a #205-family silent wrong answer. Assert the emitted Painless directly, never via .sql alone.
⚠️ Do not widen the operand productions while in here: identifierWithValue already reaches them via identifierWithIntervalFunction, and inserting an alternative before it breaks CAST('2025-01-01' + INTERVAL 1 DAY AS DATE) (measured) — the alternation commits to the first succeeding alternative and a later sequence failure never backtracks.
Found 2026-09-04 while specifying Epic 21 (Core SQL Front Door), by running the real
app.softnetwork.elastic.sql.parser.Parsercompiled frommain(ac54a079).Measured — all reject
The failing production is the target-type regex, not the operand.
Why it matters
CAST(x AS SIGNED)/AS UNSIGNEDis what Tableau's MySQL dialect generates — the dialect Epic 19 captured 89 of its 94 corpus rejections from. Parameterised types (DECIMAL(p,s),CHAR(n)) and the alias names (NUMERIC,TEXT) are standard across MySQL / PostgreSQL / SQL-92 generators.Note — this supersedes a false filing
#267 claimed the operand surface rejected bare literals (
CAST('125' AS BIGINT)). That is false and was refuted by measurement — all four spellings accept literals today. The operand surface was never the gap; this one is. #267 is being closed as not-reproducible; this issue is not a re-purposing of that number.Scope
The conversion target-type production in
sql/src/main/scala/app/softnetwork/elastic/sql/parser/. Each accepted type needs an explicit ES-type mapping decision — an alias that silently resolves to the wrong numeric type, or a parameterised precision that looks honoured but is ignored, is a #205-family silent wrong answer. Assert the emitted Painless directly, never via.sqlalone.identifierWithValuealready reaches them viaidentifierWithIntervalFunction, and inserting an alternative before it breaksCAST('2025-01-01' + INTERVAL 1 DAY AS DATE)(measured) — the alternation commits to the first succeeding alternative and a later sequence failure never backtracks.