Skip to content

feat(session): track sql_mode per session; name @@var columns as written - #57

Merged
luthermonson merged 1 commit into
mainfrom
feat/sql-mode
Oct 23, 2026
Merged

luthermonson merged 1 commit into
mainfrom
feat/sql-mode

Conversation

@luthermonson

Copy link
Copy Markdown
Contributor

sql_mode

  • SET [SESSION|LOCAL] [@@[session.]]sql_mode {=|:=} <value> is recorded per session. The value can be a literal, DEFAULT, any expression (evaluated with the current mode substituted for @@sql_mode, so REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '') works), or a bound ? (prepared path). SELECT @@sql_mode / @@SESSION.sql_mode reads the recorded value back. @@GLOBAL.sql_mode is always '', and SET GLOBAL|PERSIST changes nothing on the connection, as on MySQL.
  • Recorded, not enforced. A warning is logged when a session sets a non-empty mode. The default stays '', because litewire enforces none of MySQL 8.4's default modes; reporting them would claim checks that never happen.

@@variables

  • @@SESSION.x / @@GLOBAL.x / @@LOCAL.x are parsed case-insensitively. Bug fixed: SELECT @@SESSION.sql_mode used to read a variable named SESSION and return NULL.
  • Result columns are named as written (@@SESSION.sql_mode) or by their alias, because PHP reads $row['@@sql_mode'].
  • A select list that mixes @@vars with anything else (SELECT @@version, NOW()) goes to the parser. Previously everything except the variables was silently dropped. select @@version_comment limit 1 (the mysql CLI's connect probe) still works.

Documented and pinned: non-strict differences

These were measured over the wire on rusqlite and Turso and compared against MySQL 8.4.11. The comparison table and the decision are in docs/sql-translation.md under "sql_mode", and tests/mysql_sql_mode.rs pins them.

  • An empty string written to an INTEGER column stays text. MySQL non-strict stores 0, and MySQL strict rejects it. On litewire n = 0 is false, n > 5 is true, ORDER BY sorts it after every number, and SUM/n + 1 treat it as 0. No coercion for now: the translator does not know column types. The doc describes the schema-aware session approach as a follow-up.
  • Bare GROUP BY columns come from the first row in scan order on both engines. With MIN/MAX in the select, SQLite and Turso differ: SQLite applies its min/max bare-column rule and Turso does not.

SET [SESSION] sql_mode = <literal | DEFAULT | expression over @@sql_mode | ?>
is recorded by the session and read back by SELECT @@sql_mode; @@global
stays ''. Recorded, not enforced (warning). @@SESSION.x / @@GLOBAL.x are
parsed case-insensitively (@@SESSION.sql_mode used to read a variable
named SESSION and return NULL) and result columns are named as written or
by alias, as MySQL does. Select lists mixing @@vars with other items go
to the parser instead of being answered with only the variables.

Documents the non-strict differences (empty string in INTEGER columns stays
text; bare GROUP BY columns; MIN/MAX bare-column rule differs between
SQLite and Turso) with the coercion decision, pinned by
tests/mysql_sql_mode.rs.
@luthermonson
luthermonson merged commit f5154bb into main Oct 23, 2026
9 of 10 checks passed
@luthermonson
luthermonson deleted the feat/sql-mode branch October 23, 2026 05:21
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