132 lines
8.1 KiB
Markdown
132 lines
8.1 KiB
Markdown
# MySQL schema fidelity
|
|
|
|
The MySQL reader/writer preserves the table-schema features below. It generates
|
|
DDL for **new tables in existing databases**, not migrations or data copies.
|
|
MySQL 8.4 / InnoDB is exercised by the live suite. The reader uses MySQL 8.0.23+
|
|
metadata (including functional indexes, checks, spatial metadata, and invisible
|
|
columns); older MySQL versions and the `mariadb` alias are not certified by this
|
|
suite and may return explicit metadata-query errors.
|
|
|
|
## Conversion diagnostics
|
|
|
|
MySQL output warns on stderr when it encounters known unsupported features.
|
|
Add `--strict-conversion` to reject these conversions before opening an output
|
|
file or connecting to an output database:
|
|
|
|
```bash
|
|
relspec convert --from mysql --from-conn "$MYSQL_DSN" \
|
|
--to mysql --to-path schema.sql --strict-conversion
|
|
|
|
relspec convert --from json --from-path schema.json \
|
|
--to mysql --to-path schema.sql --strict-conversion --dry-run
|
|
```
|
|
|
|
The flag also applies to MySQL output from `batch`, `split`, and schema jobs.
|
|
Jobs can set `options.strict_conversion: true`. Library callers use
|
|
`writers.WriterOptions.StrictConversion`; `Warning func(string)` collects
|
|
non-strict diagnostics instead of printing them. `mysql.Writer.Statements`
|
|
performs the same preflight without opening a destination and returns structured
|
|
SQL statements suitable for execution without splitting on semicolons.
|
|
|
|
Strict conversion currently covers **MySQL output**. It is not a general
|
|
losslessness check for other writers or a validator of arbitrary SQL fragments.
|
|
Warnings identify the object and omitted or changed feature. Inspect them before
|
|
using non-strict output; unsupported index types are omitted, while a partial
|
|
index's predicate and INCLUDE columns cannot be represented in MySQL.
|
|
|
|
## MySQL capability matrix
|
|
|
|
| Feature | Reader → model | Model → MySQL DDL |
|
|
| --- | --- | --- |
|
|
| Ordered columns, nullability, primary/composite keys | Preserved | Preserved |
|
|
| Unique/composite keys | Preserved, including backing indexes | Preserved once; no duplicate unique index |
|
|
| Foreign/composite keys and DELETE/UPDATE actions | Preserved | Added after all tables, allowing forward references/cycles |
|
|
| CHECK and NOT ENFORCED CHECK | Preserved | Preserved |
|
|
| BTREE, FULLTEXT, SPATIAL indexes | Preserved | Emitted; engine restrictions still apply |
|
|
| Expression/prefix/descending/invisible index parts | Preserved in `Index.KeyParts` and metadata | Preserved |
|
|
| HASH indexes | Preserved | Engine-dependent; incompatible engine produces a diagnostic |
|
|
| Integer unsignedness; mediumint; enum/set; binary/blob/text variants | Canonical type plus native declaration | Native declaration preserved |
|
|
| Length, numeric precision/scale, fractional seconds | Typed dimensions plus native declaration | Preserved; canonical dimensions also supported |
|
|
| Defaults, including SQL expressions, bit/binary literals and multiline text | Values plus native SQL spelling from SHOW CREATE | Preserved |
|
|
| Auto-increment and current next value | Preserved | Preserved |
|
|
| Stored/virtual generated columns, ON UPDATE, invisible columns | Preserved | Preserved |
|
|
| Engine, table/column collation, charset and comments | Preserved | Preserved |
|
|
| Views, triggers, routines, events, partitioned tables | Names recorded in `mysql_unsupported` | Diagnostic; bodies/partition definitions are not emitted |
|
|
| Nonempty table CREATE_OPTIONS; native parser/storage/engine attributes; spatial SRID | Recorded as unsupported attributes | Diagnostic; not emitted |
|
|
| Partial/INCLUDE indexes, unsupported index methods | Retained when supplied in the model | Diagnostic |
|
|
| Deferrable constraints, identity semantics, timestamptz, jsonb storage | Retained when supplied in the model | Diagnostic for unsupported/different semantics |
|
|
| Standalone sequences/enums/domains, ownership/permissions, scripts and dialect directives | Retained when supplied in the model | Diagnostic; not emitted |
|
|
| Data, grants, users, server/plugin configuration | Outside the reader's schema contract | Outside the writer's contract |
|
|
|
|
Diagnostics depend on the objects visible to the connection account. They cover
|
|
known modeled/discovered features, not every engine/plugin extension. The server
|
|
still validates SQL expressions, engine rules, and references at execution time.
|
|
For example, source and target engines must support the constraints requested.
|
|
|
|
## Preservation across intermediate formats
|
|
|
|
| Path | Scope |
|
|
| --- | --- |
|
|
| MySQL → model → MySQL | Live-tested for the features above on MySQL 8.4 / InnoDB |
|
|
| MySQL → JSON → model → MySQL | Live-tested; preserves typed index parts and MySQL metadata |
|
|
| MySQL → YAML → model → MySQL | YAML serializes the same fields/metadata; covered by the live round-trip test |
|
|
| Other source/target formats | Their own mappings apply; MySQL-specific metadata and semantics are not certified to survive |
|
|
|
|
Native declarations and defaults are stored in column metadata as `mysql_type`
|
|
and `mysql_default_sql`. Reader-generated signatures (`mysql_type_signature`,
|
|
`mysql_default_value`) prevent these spellings from silently overriding edited
|
|
types/dimensions/defaults. Editing canonical dimensions invalidates the native
|
|
type signature, produces a diagnostic, and uses the canonical mapping instead.
|
|
For a binary default, the logical default is its SQL hex/literal spelling so it
|
|
survives serialization without invalid UTF-8.
|
|
|
|
Other metadata includes `mysql_charset`, `mysql_generation_storage`,
|
|
`mysql_default_expression`, `mysql_on_update`, `mysql_invisible`, table
|
|
`mysql_engine` / `mysql_collation` / `mysql_auto_increment`, index
|
|
`mysql_visible`, and check `mysql_enforced`. Unknown `mysql_*` metadata produces
|
|
a diagnostic. For a manually authored expression default, set
|
|
`mysql_default_expression: true`; otherwise strings are literal values.
|
|
`Index.KeyParts` is authoritative when present; `Index.Columns` remains the
|
|
compatibility representation for simple indexes.
|
|
|
|
Raw native type declarations, default SQL, generation/check/index expressions,
|
|
and ON UPDATE expressions are executable SQL input. Lowercasing changes names
|
|
and structured index parts but leaves expressions untouched; update references
|
|
inside raw SQL yourself when using `--lowercase`.
|
|
|
|
## Applying the output
|
|
|
|
Create the destination database/schema first. Qualified names are preserved,
|
|
including foreign-key target schemas. Adjust them explicitly when restoring to
|
|
a different database. Output assumes standard MySQL backslash escaping;
|
|
`NO_BACKSLASH_ESCAPES` or `ANSI_QUOTES` on the source produces a conversion
|
|
diagnostic, and live execution refuses these target modes before DDL. File consumers must use the same
|
|
supported mode. Other SQL-mode incompatibilities surface as server errors.
|
|
|
|
`CREATE TABLE IF NOT EXISTS` does not reconcile existing definitions. Foreign
|
|
keys use `ALTER TABLE ADD CONSTRAINT` and therefore repeated application can
|
|
fail on existing constraints. This is creation DDL, not a rerunnable migration.
|
|
Live execution stops on the first SQL error by default. Explicit
|
|
`ContinueOnError` attempts later statements and still returns an error if any
|
|
fail. MySQL DDL implicitly commits; `AtomicExecution` is rejected. PostgreSQL's
|
|
shared execution-report support is not yet implemented for this writer.
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
./tests/dbtest/dbtest.sh test mysql
|
|
# Or use your own disposable database:
|
|
RELSPEC_TEST_MYSQL_CONN="$MYSQL_DSN" go test -mod=vendor ./pkg/readers/mysql ./pkg/writers/mysql
|
|
```
|
|
|
|
The live tests compare MySQL's `SHOW CREATE TABLE` definitions, normalizing only
|
|
temporary target-name suffixes and nonsemantic ordinary-index display order.
|
|
They re-read the target, exercise constraint enforcement/default values, and
|
|
verify unsupported objects produce warnings or strict failures without touching
|
|
an existing output file. Test fixtures are removed after each run.
|
|
|
|
Metadata references: [COLUMNS](https://dev.mysql.com/doc/refman/8.4/en/information-schema-columns-table.html),
|
|
[STATISTICS](https://dev.mysql.com/doc/refman/8.4/en/information-schema-statistics-table.html),
|
|
[TABLE_CONSTRAINTS](https://dev.mysql.com/doc/refman/8.4/en/information-schema-table-constraints-table.html),
|
|
and [REFERENTIAL_CONSTRAINTS](https://dev.mysql.com/doc/refman/8.4/en/information-schema-referential-constraints-table.html).
|