Skip to content

feat(mysql): restore mysqldumps with their indexes; scope index names to their table - #58

Merged
luthermonson merged 2 commits into
mainfrom
feat/ddl-indexes
Oct 23, 2026
Merged

luthermonson merged 2 commits into
mainfrom
feat/ddl-indexes

Conversation

@luthermonson

Copy link
Copy Markdown
Contributor

Restoring a MySQL 8.4 mysqldump through litewire now brings back the indexes, and DDL with MySQL-only column syntax no longer fails.

Indexes

  • Inline KEY / INDEX / UNIQUE KEY in CREATE TABLE used to be dropped (KEY) or reduced to an anonymous UNIQUE (...) (UNIQUE KEY). That meant a restored dump had no secondary indexes, and SHOW INDEX reported unique keys as sqlite_autoindex_*. Each key now becomes a named CREATE [UNIQUE] INDEX emitted after the table. It is IF NOT EXISTS when the table is. Unnamed keys get MySQL's default name (first column, then _2, ...). FULLTEXT/SPATIAL keys are still dropped.
  • Per-table index names. MySQL scopes index names to their table, while SQLite scopes them to the whole database, and dumps reuse key names across tables (list_idx on two tables in the fixture). So MySQL index k on table t is created as SQLite index `t__k`. SHOW INDEX, information_schema.statistics and SHOW COLUMNS' Key report it as k.
  • DROP INDEX k ON t, ALTER TABLE t DROP INDEX k, and ALTER TABLE t DROP KEY k (which sqlparser cannot parse; it is normalized to DROP INDEX) all drop t__k. Compat: an index created under its bare name by an older litewire is still dropped. On "no such index", the session drops the one index of t whose name is k.
  • An unnamed ALTER TABLE t ADD INDEX (cols) used to emit invalid SQL (CREATE INDEX ON t). It now gets MySQL's default name.
  • ASC/DESC in an inline key's column list (KEY k (col DESC), which mysqldump writes) is dropped because sqlparser cannot parse it there. A standalone CREATE INDEX keeps it.

Columns and literals

  • Column CHARACTER SET / COLLATE / COMMENT / ON UPDATE CURRENT_TIMESTAMP are dropped instead of reaching SQLite, which rejected them. This applies in both CREATE TABLE and ALTER TABLE ... ADD. Documented behaviour differences: text comparisons are binary (case-sensitive), unlike MySQL's _ci default, and ON UPDATE is not emulated.
  • Charset introducers: _binary 'abc' becomes X'616263' (a BLOB), and _utf8mb4'x' becomes 'x'.

Tests

  • crates/litewire/tests/mysql_dump_restore.rs replays an unedited MySQL 8.4.11 mysqldump --hex-blob (tests/fixtures/mysqldump_8_4.sql, from a synthetic schema written for the test). The dump has conditional comments, LOCK/UNLOCK, DISABLE/ENABLE KEYS, mixed utf8mb3/utf8mb4 collations at table and column level, ROW_FORMAT/AUTO_INCREMENT/COMMENT table options, column COLLATE/COMMENT/ON UPDATE, ENUM/DECIMAL, prefix-length keys, a key name reused across tables, and string escapes. The test adds a ~700 KB extended INSERT. It runs on rusqlite and Turso and checks tables, SHOW INDEX names/order/uniqueness, data (unicode, escapes, blob bytes), UNIQUE enforcement (1062), and AUTO_INCREMENT continuation.
  • The legacy bare-name index drop and the charset introducers are covered on both backends.
  • Unit tests cover key expansion, default names, DROP forms, column-option stripping, and DESC handling.

Docs: docs/sql-translation.md has an updated DDL section and a new "Restoring a mysqldump" guide. The guide calls out that views/triggers/routines inside /*!50001 */ are skipped and that dumps with binary data need --hex-blob.

… to their table

Inline KEY / INDEX / UNIQUE KEY in CREATE TABLE (previously dropped, or
reduced to an anonymous UNIQUE) become named CREATE [UNIQUE] INDEX
statements. MySQL index names are per table and SQLite's per database, so
index k on t is created as t__k and reported as k by SHOW INDEX /
information_schema.statistics; DROP INDEX k ON t and ALTER TABLE t DROP
{INDEX|KEY} k drop it, falling back to an index of t created under the bare
name by an older litewire. Unnamed keys get MySQL's default names; an
unnamed ALTER ... ADD INDEX no longer emits invalid SQL.

Column CHARACTER SET / COLLATE / COMMENT / ON UPDATE and charset
introducers (_binary '...' becomes a blob literal) no longer reach SQLite.

tests/mysql_dump_restore.rs replays an unedited MySQL 8.4 mysqldump
--hex-blob (fixtures/) plus a ~700 KB extended INSERT on both backends and
checks schema, keys, data, key enforcement and AUTO_INCREMENT continuation.
Restore guide in docs/sql-translation.md.
@luthermonson
luthermonson merged commit 741c4ee into main Oct 23, 2026
5 checks passed
@luthermonson
luthermonson deleted the feat/ddl-indexes branch October 23, 2026 05:50
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