Skip to content

Add ANSI_QUOTES and SQL mode validation#452

Draft
JanJakes wants to merge 5 commits into
trunkfrom
ansi-quotes
Draft

Add ANSI_QUOTES and SQL mode validation#452
JanJakes wants to merge 5 commits into
trunkfrom
ansi-quotes

Conversation

@JanJakes

@JanJakes JanJakes commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

  • store SQL modes internally as their native MySQL bitmap and serialize them in canonical bit order
  • validate named and numeric SQL mode assignments for the configured MySQL version with MySQL-compatible errors
  • add ANSI_QUOTES handling to the PHP and native MySQL lexers
  • expand the composite ANSI mode while retaining the original mode
  • treat backslashes literally in quoted identifiers in both lexer implementations
  • regenerate native lexer constants and repair the constants generator's monorepo path

Why

The driver previously stored arbitrary SQL mode names, accepted invalid assignments, treated double-quoted text as string literals regardless of SQL mode, did not expand ANSI, and applied string backslash escaping rules to quoted identifiers. The native lexer also lacked the corresponding behavior.

Impact

@@sql_mode now follows MySQL's bitmap order, duplicate modes collapse, invalid assignments fail without changing session state, and mode availability follows the emulated MySQL version. Queries using ANSI_QUOTES or ANSI parse double-quoted identifiers correctly in PHP and native configurations, including identifiers containing or ending in backslashes.

Testing

  • pure-PHP PHPUnit suite: 783 tests, 1,428,468 assertions
  • native-extension PHPUnit suite: 783 tests, 1,429,439 assertions
  • composer run check-cs
  • cargo fmt --check and cargo test
  • native extension release build and verification

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🤖 Lexer benchmark

Changes to lexer-related files were detected and triggered a benchmark:

Config Base (QPS) This PR (QPS) Speedup
no JIT 85,495 84,801 0.99×
tracing JIT 174,279 173,646 1.00×

Note: Hosted runners are noisy, and absolute numbers vary. Treat the results with caution and verify them locally.

To reproduce locally:

cd packages/mysql-on-sqlite && composer run bench-lexer

JanJakes added 5 commits July 15, 2026 19:10
Map supported SQL mode names to their native MySQL bit values and use the bitmap as the driver's internal representation. Serialize active modes by bit position so duplicates collapse and @@sql_mode follows MySQL's canonical order.
Validate SQL mode names and numeric masks before changing the session state. Report invalid values with MySQL's SQLSTATE 42000 and error 1231, while retaining MySQL's handling for empty list components and incorrect value types.
When ANSI_QUOTES is active, MySQL treats a double-quoted sequence as a
quoted identifier rather than a string literal. Emulate this in the lexer
by emitting a backtick-quoted identifier token for double-quoted text when
the mode is set, mirroring how NO_BACKSLASH_ESCAPES already alters
tokenization. The driver already forwards its active SQL modes to the lexer,
so no further wiring is needed.

See: https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html#sqlmode_ansi_quotes
MySQL's composite ANSI mode is shorthand for a set of component modes. Expand
it when sql_mode is set and store the resulting list, so that "@@sql_mode" and
individual mode checks reflect the components:

  REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY

REAL_AS_FLOAT and ONLY_FULL_GROUP_BY are stored but not yet respected by the
emulation.

The driver is the source of truth for SQL modes, but the lexer also recognizes
the composite ANSI mode directly so it stays correct when used standalone,
applying the components that affect tokenization: PIPES_AS_CONCAT, IGNORE_SPACE,
and ANSI_QUOTES.

See: https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html#sqlmode_ansi
MySQL does not process backslash escape sequences inside quoted identifiers;
the bounding quote is escaped only by doubling it. The lexer was applying
string-literal backslash escaping to backtick identifiers (and, with the new
ANSI_QUOTES support, to double-quoted identifiers), both when scanning for the
closing quote and when unquoting the value.

As a result, an identifier like `a\nb` resolved to "a<newline>b", and `a\`
(a trailing backslash) failed to tokenize because the backslash was treated as
escaping the closing quote. Restrict backslash escaping to string literals so
identifiers preserve backslashes verbatim.

See: https://dev.mysql.com/doc/refman/8.4/en/identifiers.html
@JanJakes JanJakes changed the title Add ANSI_QUOTES SQL mode support Add ANSI_QUOTES and SQL mode validation Jul 15, 2026
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