parser: honour inline column-level PRIMARY KEY / UNIQUE#81
Conversation
AGENTS.md "In scope (v1)" lists "inline column-level PK / UNIQUE / REFERENCES", but only the REFERENCES path was actually wired up (parser/parser.go's column loop checked `cd.Type.Options.Reference`). vitess parses `id INT PRIMARY KEY` and `email VARCHAR(255) UNIQUE` as a column attribute (`cd.Type.Options.KeyOpt = ColKeyPrimary` / `ColKeyUnique` / `ColKeyUniqueKey`) rather than promoting them to the table-level Indexes / Constraints buckets, so both forms were silently dropped. Plan / apply / dump confirmed (`SHOW CREATE TABLE` after apply showed neither the PK nor the UNIQUE index). Add `applyInlineColumnKey` to mirror the table-level path's behaviour from `addIndex`'s IndexTypePrimary / IndexTypeUnique cases: - `ColKeyPrimary` → PRIMARY constraint + PRIMARY index, with the column forced to NotNull (MySQL silently does that for PK columns; mirror so the dump round-trip stays stable). - `ColKeyUnique` / `ColKeyUniqueKey` → UNIQUE index named after the column (matches MySQL's auto-naming and the table-level UNIQUE case at parser.go's IndexTypeUnique branch). - Other ColKey* values (None, Spatial, Fulltext, bare Key) aren't valid column-level MySQL attributes — pass through silently to match the parser's existing "ignore unmodelled shapes" policy. Tests: TestParseInlineColumnPrimaryKey / TestParseInlineColumnUnique in parser_test.go pin the parsed model. Integration fixture testdata/apply/inline_column_primary_key_and_unique.yml exercises the full plan → apply → re-plan-empty round-trip; without the fix the inline PK / UNIQUE silently drop and verify_no_drift catches the regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #81 +/- ##
=======================================
Coverage 86.62% 86.62%
=======================================
Files 30 30
Lines 3237 3268 +31
=======================================
+ Hits 2804 2831 +27
- Misses 267 269 +2
- Partials 166 168 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR updates the SQL parser to correctly promote Vitess’s inline column-level key attributes (PRIMARY KEY, UNIQUE [KEY]) into myschema’s internal table model, preventing these constraints from being silently dropped during apply and ensuring stable plan/apply/dump round-trips.
Changes:
- Parse inline column-level
PRIMARY KEY/UNIQUE [KEY]via a newapplyInlineColumnKeyhelper inparser/parser.go. - Add unit coverage for inline PK/UNIQUE promotion and PK-implied
NOT NULLbehavior. - Add an end-to-end apply fixture that verifies no drift when inline PK/UNIQUE are present.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
parser/parser.go |
Promotes inline column KeyOpt (PRIMARY/UNIQUE) into Constraints/Indexes during CREATE TABLE parsing. |
parser/parser_test.go |
Adds unit tests validating inline PK/UNIQUE promotion and PK-implied NOT NULL. |
testdata/apply/inline_column_primary_key_and_unique.yml |
Adds integration fixture to pin round-trip behavior and prevent regression. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- applyInlineColumnKey: rewrite the duplicate-handling comment.
The previous text claimed addIndex's IndexTypePrimary case has an
"existing PRIMARY KEY equality check" that would let the duplicate
through — that's wrong, addIndex unconditionally overwrites
Constraints["PRIMARY"] / Indexes["PRIMARY"]. The skip is still
correct (same end state when both forms reference the same column,
MySQL-rejected at apply when they don't); explain that instead.
- TestParseInlineColumn{PrimaryKey,Unique} comments referenced
parser.go:608 / parser.go:617. Replace with stable references
("addIndex's IndexTypePrimary case", "addIndex's IndexTypeUnique
case") so the comments don't rot when the file is edited.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Coverage gap audit on the inline column-level PK / UNIQUE work: - New `AUTO_INCREMENT combines with inline PRIMARY KEY` sub-test pins the most common real-world surrogate-key shape (`id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY`). vitess holds KeyOpt and Autoincrement on different fields, so the promotion must not clobber AutoIncrement — pin so a refactor that mishandles the column attributes surfaces in CI. - New `two inline PRIMARY KEYs: first column wins` sub-test reaches applyInlineColumnKey's idempotent skip branch (previously uncovered — vitess parses two-inline-PK SQL without error even though MySQL rejects at apply, so the second column hits the skip-when-exists guard). Pins the parser-side "first wins" precedence; MySQL still surfaces the duplicate-PK at apply. - Document the dup-index guard in applyInlineColumnKey's ColKeyUnique case as defensive: it's unreachable in the current architecture (column loop runs before table-level Indexes; column names are unique-checked upstream), kept for symmetry with addIndex's IndexTypeUnique branch and to fail closed under a future pass-order refactor. applyInlineColumnKey coverage: 84.6% → 92.3%. The remaining 7.7% is the documented unreachable defensive branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Audit triggered by the inline column-level PRIMARY KEY / UNIQUE bug fix on PR #81. Probed adjacent column / table / index attributes that vitess parses but myschema might silently drop. Results: High (silent data loss, not just feature drop): - vitess `Parse2` swallows some syntax errors as WARN logs and returns a partially-parsed AST; myschema treats that as success and can emit an empty `CREATE TABLE t ();` for inputs vitess rejects. Repro: COLUMN_FORMAT + STORAGE on a column. Medium (silent fidelity gaps; parser populates the model but the emitter / catalog reader don't): - Column-level INVISIBLE (MySQL 8.0+) dropped — catalog has it via EXTRA, parser side doesn't. - SRID on spatial columns dropped — catalog surfaces it via ST_GEOMETRY_COLUMNS, parser side doesn't read `Options.SRID`. - Table-level ROW_FORMAT / KEY_BLOCK_SIZE / COMPRESSION / ENCRYPTION dropped — `applyTableOption` only handles ENGINE / CHARSET / COLLATE / COMMENT / AUTO_INCREMENT. - Index-level KEY_BLOCK_SIZE dropped — `addIndex` doesn't read the option, `Index.SQL()` doesn't emit it. Each entry includes the repro path, where in the code to look, and the fix sketch. Logged to TODO so the next contributor working in that area can pick them up; no code change here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs: log silent-drop audit findings (TODO follow-ups from PR #81)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The previous comment opened with "Both columns get NotNull forced" which is wrong — only column `a` (the first inline PK) gets the forced NotNull from its own promotion. Column `b` hits the skip branch in applyInlineColumnKey and is left untouched; its NotNull flag stays at whatever vitess parsed (here, implicit nullable INT because the source SQL doesn't write NOT NULL on `b`). Reword so the lead matches the rest of the comment instead of contradicting it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
AGENTS.md"In scope (v1)" lists "inline column-level PK / UNIQUE / REFERENCES", but onlyREFERENCESwas actually wired up.parser/parser.go's column loop checkedcd.Type.Options.Reference(FK) but ignoredcd.Type.Options.KeyOpt, so vitess'sColKeyPrimary/ColKeyUnique/ColKeyUniqueKeysilently dropped:This PR adds
applyInlineColumnKeyto mirror the table-level path's behaviour:ColKeyPrimary→ PRIMARY constraint + PRIMARY index, column forced toNotNull(MySQL implicitly does this for PK columns; mirror so dump round-trips stay stable).ColKeyUnique/ColKeyUniqueKey→ UNIQUE index named after the column (matches MySQL's auto-naming and the table-level path atparser.go'sIndexTypeUniquecase).ColKey*values (None, spatial, fulltext, bareKey) aren't valid column-level attributes — pass through silently to match the parser's existing "ignore unmodelled shapes" policy.Test plan
TestParseInlineColumnPrimaryKey(explicit + implicitNOT NULL),TestParseInlineColumnUnique(UNIQUE+UNIQUE KEYkeywords).testdata/apply/inline_column_primary_key_and_unique.ymlexercises plan → apply → re-plan-empty round-trip withverify_no_drift: true. Without the fix the inline PK / UNIQUE silently drop and the round-trip never closes.make lintclean,make testall six packages green.SHOW CREATE TABLEaftermyschema applyagainst MySQL 8.0 confirmsPRIMARY KEYandUNIQUE KEY emailland as expected.🤖 Generated with Claude Code