diff --git a/persistent-mysql/Database/Persist/MySQL.hs b/persistent-mysql/Database/Persist/MySQL.hs index 1459775a2..d54612feb 100644 --- a/persistent-mysql/Database/Persist/MySQL.hs +++ b/persistent-mysql/Database/Persist/MySQL.hs @@ -1766,6 +1766,35 @@ putManySql' (filter isFieldNotGenerated -> fields) ent n = q , Util.commaSeparated updates ] +-- | Generate the default foreign key constraint name for a given source table and +-- source column name, truncated to fit MySQL's 64 character identifier limit. +-- +-- MySQL, unlike Postgres, does not silently truncate identifiers that are too long; +-- it raises an error instead (\"Identifier name ... is too long\"). Without this, +-- persistent would suggest foreign key constraint names that MySQL simply refuses to +-- create. This mirrors the truncation approach @persistent-postgresql@ already uses +-- for the same underlying problem, just with MySQL's 64 character limit instead of +-- Postgres' 63. +refName :: EntityNameDB -> FieldNameDB -> ConstraintNameDB +refName (EntityNameDB table) (FieldNameDB column) = + let + overhead = T.length $ T.concat ["_", "_fkey"] + (fromTable, fromColumn) = shortenNames overhead (T.length table, T.length column) + in + ConstraintNameDB $ + T.concat [T.take fromTable table, "_", T.take fromColumn column, "_fkey"] + where + maximumIdentifierLength :: Int + maximumIdentifierLength = 64 + + shortenNames :: Int -> (Int, Int) -> (Int, Int) + shortenNames overhead (x, y) + | x + y + overhead <= maximumIdentifierLength = (x, y) + | x > y = shortenNames overhead (x - 1, y) + | otherwise = shortenNames overhead (x, y - 1) + mysqlMkColumns :: [EntityDef] -> EntityDef -> ([Column], [UniqueDef], [ForeignDef]) -mysqlMkColumns allDefs t = mkColumns allDefs t emptyBackendSpecificOverrides +mysqlMkColumns allDefs t = + mkColumns allDefs t $ + setBackendSpecificForeignKeyName refName emptyBackendSpecificOverrides diff --git a/persistent-mysql/persistent-mysql.cabal b/persistent-mysql/persistent-mysql.cabal index 778278bf5..bc6a8afaa 100644 --- a/persistent-mysql/persistent-mysql.cabal +++ b/persistent-mysql/persistent-mysql.cabal @@ -1,5 +1,5 @@ name: persistent-mysql -version: 2.13.1.6 +version: 2.13.1.7 license: MIT license-file: LICENSE author: Felipe Lessa , Michael Snoyman diff --git a/persistent-mysql/test/main.hs b/persistent-mysql/test/main.hs index a2198a057..1644834a1 100644 --- a/persistent-mysql/test/main.hs +++ b/persistent-mysql/test/main.hs @@ -158,8 +158,8 @@ main = do , CustomPrimaryKeyReferenceTest.migration , MigrationColumnLengthTest.migration , TransactionLevelTest.migration - , -- , LongIdentifierTest.migration - ForeignKey.compositeMigrate + , LongIdentifierTest.migration + , ForeignKey.compositeMigrate ] PersistentTest.cleanDB ForeignKey.cleanDB @@ -237,10 +237,7 @@ main = do MigrationIdempotencyTest.specsWith db MigrationTest.specsWith db CustomConstraintTest.specs db - -- 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 + LongIdentifierTest.specsWith db GeneratedColumnTestSQL.specsWith db JSONTest.specs diff --git a/persistent-test/src/LongIdentifierTest.hs b/persistent-test/src/LongIdentifierTest.hs index 6480ebc76..dbe68330f 100644 --- a/persistent-test/src/LongIdentifierTest.hs +++ b/persistent-test/src/LongIdentifierTest.hs @@ -19,7 +19,7 @@ import Init -- This test creates very long identifier names. The generated foreign key is over the length limit for Postgres and MySQL -- persistent-postgresql handles this by truncating foreign key names using the same algorithm that Postgres itself does (see 'refName' in Postgresql.hs) --- MySQL currently doesn't run this test, and needs truncation logic for it to pass. +-- persistent-mysql does the same, using MySQL's 64 character limit (see 'refName' in MySQL.hs) share [mkPersist sqlSettings, mkMigrate "migration"] [persistLowerCase|