Skip to content

docs: document CHECK-on-renamed-column limitation, drop from TODO#98

Merged
winebarrel merged 5 commits into
mainfrom
docs-check-rename-caveat
May 6, 2026
Merged

docs: document CHECK-on-renamed-column limitation, drop from TODO#98
winebarrel merged 5 commits into
mainfrom
docs-check-rename-caveat

Conversation

@winebarrel

@winebarrel winebarrel commented May 6, 2026

Copy link
Copy Markdown
Owner

Summary

The "CHECK constraint referencing a renamed column blocks the rename" TODO was framed as a fixable diff-layer bug. Probing MySQL's actual behaviour shows the constraint is harder than it looked:

  • `RENAME COLUMN` with an active CHECK that references the column always errors with `Error 3959 Check constraint 'X' uses column 'Y'…`.
  • There is no MySQL-side bypass:
    • `SET foreign_key_checks=0` doesn't apply (CHECK and FK are independent).
    • Even `DROP CHECK` → `RENAME COLUMN` → `ADD CONSTRAINT … CHECK (old_name …)` is rejected with `Error 1054 Unknown column` because MySQL itself does not auto-rewrite CHECK bodies on rename.

So the user always has to spell out the new column name in the new CHECK body, regardless of what myschema does. The only remaining question was whether myschema should auto-rewrite the catalog-side CHECK definition (so the diff doesn't fire DROP+ADD at all) and reorder the buckets so DROP CHECK runs before RENAME COLUMN.

Decision: don't fix in code. The auto-rewrite would parse every CHECK body through vitess and walk the AST — significant code that isn't justified by how rare the case is. The user's manual `DROP CHECK` step is a minute of work.

Changes

  • `CAVEATS.md`: new "Renaming a column referenced by a CHECK constraint" section. Documents the MySQL rule, the absence of a bypass, the out-of-band workaround (run `mysql … 'ALTER TABLE t DROP CHECK chk_x;'` against the live database before invoking `myschema apply`), and the rationale for not auto-fixing. Explicitly notes that `-- myschema:execute` cannot be used here — execute blocks run after every other DDL bucket, so a `DROP CHECK` inside `execute` would fire after the failing `RENAME COLUMN` and never get the chance to clear the path.
  • `TODO.md`: drop the corresponding entry. The limitation is now part of the documented contract, not a deferred fix.

Test plan

  • Doc-only change.
  • `make lint` clean.

🤖 Generated with Claude Code

The TODO entry framed this as a fixable bug, but probing MySQL's
actual behaviour revealed that:

- `RENAME COLUMN` with an active CHECK constraint that
  references the column always errors with `Error 3959`.
- There is no MySQL-side bypass — `SET foreign_key_checks=0`
  doesn't apply (CHECK and FK are unrelated), and even a
  `DROP CHECK → RENAME COLUMN → ADD CHECK (old_name …)`
  sequence is rejected with `Error 1054 Unknown column` on
  the re-add. MySQL itself does not auto-rewrite CHECK bodies
  on rename.

So the user always has to spell out the new column name in the
new CHECK body regardless of what myschema does. The remaining
question was whether myschema should also drop the CHECK before
emitting the RENAME, and whether to auto-rewrite the catalog
side's CHECK body so the diff doesn't even fire DROP+ADD.
Decision: do neither. The expression-rewrite path would require
parsing every CHECK body through vitess and walking the AST,
which isn't justified by how rare the column-rename-with-CHECK
case is in practice. The user's manual `DROP CHECK` step (or
a `-- myschema:execute` block) is a minute of work.

CAVEATS.md gets a new "Renaming a column referenced by a CHECK
constraint" section explaining the rule, the workaround, and
the rationale. The TODO entry is removed since the limitation
is now part of the documented contract, not a deferred fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 6, 2026 04:26
@codecov

codecov Bot commented May 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.96%. Comparing base (2b54fcf) to head (c490e42).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #98   +/-   ##
=======================================
  Coverage   86.96%   86.96%           
=======================================
  Files          30       30           
  Lines        3321     3321           
=======================================
  Hits         2888     2888           
  Misses        266      266           
  Partials      167      167           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates project documentation to reflect a MySQL limitation around renaming columns referenced by CHECK constraints, and removes a corresponding “TODO” item now considered an accepted limitation/contract.

Changes:

  • Document MySQL’s behavior/error when renaming a column referenced by an active CHECK constraint, plus rationale for not auto-fixing in myschema.
  • Add a documented workaround section for users.
  • Remove the related TODO entry now that the limitation is documented.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
CAVEATS.md Adds a new caveat section explaining CHECK+RENAME behavior and a proposed workaround.
TODO.md Removes the TODO item related to CHECK constraints blocking column renames.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CAVEATS.md Outdated
Comment thread CAVEATS.md Outdated
Comment thread CAVEATS.md Outdated
Three valid corrections on the new CAVEATS section:

- Execute groups run AFTER all other DDL buckets, not before
  (verified: diff_all.go:97 — "blocks run after every other
  DDL bucket"). My example told users to wrap the DROP CHECK
  in `-- myschema:execute`, which would actually fire AFTER
  the failing RENAME COLUMN — exactly backwards.
- The check-SQL semantics in the example were also inverted:
  myschema treats 1+ rows as "already applied, skip" and 0
  rows as "not applied yet, run." For a DROP, my example
  returned rows when the CHECK existed (so the DROP would
  skip when it should run, and try to drop again after the
  CHECK is gone).

Both errors disappear by recommending a genuinely out-of-band
pre-step instead. Rewrite the workaround to: run the DROP CHECK
by hand against the live database, then run `myschema apply`.
The diff then sees catalog has no CHECK and emits a clean
RENAME + ADD CHECK pair, both of which succeed. Add an explicit
"don't reach for `-- myschema:execute` here" paragraph that
spells out why the directive can't help.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CAVEATS.md
Comment thread CAVEATS.md Outdated
- Use the full `ADD CONSTRAINT chk_x CHECK (old_name …)` form
  in the inline narrative for consistency with the actual
  MySQL DDL syntax used elsewhere (the previous shorthand
  `ADD CHECK (...)` looked like literal DDL but isn't valid).
- PR description still recommended the `-- myschema:execute`
  workaround that the doc had since reverted; updated the PR
  body so the recommendation matches what CAVEATS now says
  (out-of-band manual `DROP CHECK` against the live database).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CAVEATS.md
Comment thread CAVEATS.md Outdated
Comment thread CAVEATS.md Outdated
Comment thread TODO.md
Four valid catches:

- CAVEATS plan example always showed `DROP CHECK`, but
  diffConstraints suppresses CHECK drops unless
  `--allow-drop=constraint` (or `=all`) is set. Document both
  shapes: with allow-drop the user sees the three-statement
  plan; without it, only the failing RENAME COLUMN plus a
  `-- skipped:` line. The MySQL Error 3959 is the same either
  way.
- Replace the Unicode circled `①` annotation in the SQL example
  with a plain ASCII `-- fails here`. The fancy character
  hurts copy/paste into terminals and grep over logs.
- Spelling: "dropped-then-readded" → "dropped-then-re-added"
  to match the "re-add" usage earlier in the same section.
- testdata/apply/inline_rename_all_kinds.yml's caveat comment
  still pointed at the deleted TODO entry. Update the pointer
  to "CAVEATS.md 'Renaming a column referenced by a CHECK
  constraint'" so the cross-reference doesn't go stale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread CAVEATS.md Outdated
The previous round added an inaccurate "without allow-drop the
DROP gets suppressed" branch to the CAVEATS section. Verified
against the actual implementation:

- diffConstraints suppresses a DROP only on the `!ok` branch —
  i.e. when the constraint is being removed entirely from
  desired.
- For the bug scenario (same name `chk_x`, different body
  because it references the renamed column) the constraint is
  present on both sides, so `ok=true`, the suppression logic
  doesn't apply, and DROP+ADD fires regardless of allow-drop.

Probed: `myschema plan` with and without --allow-drop=constraint
produced byte-identical output for the rename-with-CHECK case.

Drop the two-shape narrative and replace it with a single
correct description: the three-statement plan above is what
every user sees, and apply fails at line 1 with Error 3959.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@winebarrel winebarrel merged commit 6bd127c into main May 6, 2026
9 checks passed
@winebarrel winebarrel deleted the docs-check-rename-caveat branch May 6, 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.

2 participants