Skip to content

persistent-mysql: truncate foreign key constraint names to MySQL's 64 char limit - #1633

Open
Moferanoluwa wants to merge 1 commit into
yesodweb:masterfrom
Moferanoluwa:fix/mysql-foreign-key-name-truncation
Open

persistent-mysql: truncate foreign key constraint names to MySQL's 64 char limit#1633
Moferanoluwa wants to merge 1 commit into
yesodweb:masterfrom
Moferanoluwa:fix/mysql-foreign-key-name-truncation

Conversation

@Moferanoluwa

Copy link
Copy Markdown

Description

Fixes #1000. persistent-mysql currently generates foreign key constraint names using the shared default scheme (tableName_columnName_fkey) with no length limit. Unlike Postgres, which silently truncates over-length identifiers (worked around in persistent-postgresql via refName, added in #996), MySQL just raises an error for identifiers over 64 characters.

This adds the MySQL equivalent of that same refName override, reusing the exact same truncation algorithm persistent-postgresql already uses (approximating how the database itself truncates), just with MySQL's 64-character limit instead of Postgres' 63, wired in via the existing setBackendSpecificForeignKeyName extension point.

Evidence this is the intended fix

persistent-test/src/LongIdentifierTest.hs and its hookup in persistent-mysql/test/main.hs were already sitting there, explicitly disabled and waiting on exactly this:

-- TODO: implement automatic truncation for too long foreign keys, so we can run this test.
xdescribe
    "The migration for this test currently fails because of MySQL's 64 character limit for identifiers. See https://github.com/yesodweb/persistent/issues/1000 for details"
    $ LongIdentifierTest.specsWith db

I enabled that test (both the xdescribe wrapper and the commented-out migration registration a few lines up) rather than leaving it disabled.

Changes

  • persistent-mysql/Database/Persist/MySQL.hs — add refName, mirroring persistent-postgresql's function of the same name/signature almost exactly (maximumIdentifierLength = 64 instead of 63), and wire it into mysqlMkColumns via setBackendSpecificForeignKeyName.
  • persistent-mysql/test/main.hs — enable LongIdentifierTest, which was previously disabled specifically because this was missing.
  • persistent-test/src/LongIdentifierTest.hs — update the comment that said MySQL didn't run this test yet.
  • persistent-mysql/persistent-mysql.cabal — bump patch version (2.13.1.6 → 2.13.1.7) per CONTRIBUTING.md's versioning guide (bug fix = patch bump).

Per CONTRIBUTING.md, I'll follow up with the Changelog.md entry once I have a PR number to link.

Testing/Review Recommendations

I don't have a Haskell toolchain (no ghc/stack/cabal) available in this environment, so I was not able to compile or run this locally — please treat that as a real gap, not just a formality, and lean on CI here. What gives me confidence despite that:

  • refName's type signature and every symbol it uses (EntityNameDB, FieldNameDB, ConstraintNameDB, setBackendSpecificForeignKeyName, emptyBackendSpecificOverrides) come from Database.Persist.Sql, which MySQL.hs already imports unqualified — same import the Postgres file uses for the same symbols.
  • The function body is the Postgres implementation with only the constant changed (63 → 64); I traced the shortenNames recursion by hand rather than just assuming it carries over.
  • The now-enabled LongIdentifierTest is exactly the test the maintainers left in place for this fix (it references issue MySQL backend generates foreign keys over length limit #1000 by number in its own skip message), so CI running it is a real, existing check of correctness, not something I added ad hoc.

AI Usage

  • Tool: Claude Code (Claude Sonnet)
  • Type: Locating the existing Postgres refName implementation and the pre-wired-but-disabled LongIdentifierTest, porting the former to MySQL, and enabling the latter.
  • Scope: The four files listed above.

… char limit

persistent-mysql currently suggests foreign key constraint names using
the shared default naming scheme (tableName_columnName_fkey) with no
length limit applied. Unlike Postgres, which silently truncates
over-length identifiers (which persistent-postgresql already works
around via refName in Postgresql.hs, added in yesodweb#996), MySQL raises an
error instead: "Identifier name ... is too long".

Add an equivalent refName override for MySQL using the same truncation
algorithm persistent-postgresql already uses, just with MySQL's 64
character limit instead of Postgres' 63, and wire it in via
setBackendSpecificForeignKeyName.

persistent-test/src/LongIdentifierTest.hs and the commented-out /
xdescribe'd hookup in persistent-mysql/test/main.hs were already in
place, explicitly waiting on this (main.hs even links directly to
issue yesodweb#1000) - enabled both.

Bumped persistent-mysql's version per CONTRIBUTING.md (patch: new bug
fix). Will follow up with the Changelog.md entry once I have a PR
number to link, per the documented changelog process.

Fixes yesodweb#1000
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.

MySQL backend generates foreign keys over length limit

1 participant