fix: resolve table names case-insensitively across all executors

SQL identifiers are case-insensitive, so the engine resolves a table
named in any capitalization — but our metadata tables (keyed by
table_name / parent_table / child_table) and data/<table>.csv files use
case-sensitive TEXT '=', so an operation naming a table in a different
case than stored drifted: schema ops orphaned metadata rows, and a
wrong-case insert/update/delete silently skipped the CSV write, losing
the change on the next reload/rebuild. This contradicted ADR-0009's
stated rule (case-insensitive resolution, case-preserving display).

Add a canonical_table_name helper (resolve to the stored case via
COLLATE NOCASE, excluding sqlite_* and __rdbms_* tables) and apply it at
the entry of every table-naming executor — drop table, add/drop/rename
column, change column type, add/drop constraint, add relationship, add
index, rename table, insert/update/delete, and the advanced SQL DML —
so the live schema, the metadata, and the CSV stay in step regardless of
how the user capitalized the name. This also folds the internal-table
guard into the same lookup (executors that previously lacked it now
refuse __rdbms_*/sqlite_* as "no such table"). do_rename_table now
accepts a case-variant source too.

Column names remain matched case-sensitively (a wrong case is refused as
"no such column" — strict, but never drifting), per the scope agreed
with the user.

Tests: tests/case_insensitive_names.rs — wrong-case rename-column,
insert (survives a fresh rebuild — no data loss), add-column, drop-table,
rename-table, and add-relationship, all with fresh-rebuild round-trips.
Full suite 1909 passing / 0 failing / 1 ignored; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-26 10:04:27 +00:00
parent f7e77a86f8
commit a95c8074f3
3 changed files with 357 additions and 38 deletions
@@ -66,7 +66,16 @@ DSL commands, and SQL all use plain words.
`customers` are different identifiers if a backend would
treat them as such (we follow SQLite's case-insensitive
identifier rules at the schema level but preserve the user's
written casing in display).
written casing in display). Concretely, a command may name a
table in any capitalization (the engine resolves it
case-insensitively); every executor **canonicalizes a
user-supplied table name to its stored case** before touching
metadata or CSV (`canonical_table_name` in `db.rs`), so the
live schema, the metadata tables, and the `data/<table>.csv`
files stay in step regardless of how the user capitalized the
name. (Column names are matched case-sensitively and a wrong
case is refused as "no such column" — strict, but never
drifting.)
- **Whitespace is liberal.** Any amount of horizontal whitespace
between tokens is accepted, including around punctuation
(`,`, `:`, `(`, `)`).