Skip to content

Auto-generate foreign key constraint names when not provided#1041

Merged
dereuromark merged 6 commits into5.xfrom
fix-auto-generate-fk-constraint-name
Mar 11, 2026
Merged

Auto-generate foreign key constraint names when not provided#1041
dereuromark merged 6 commits into5.xfrom
fix-auto-generate-fk-constraint-name

Conversation

@dereuromark
Copy link
Member

Summary

  • Auto-generate foreign key constraint names when not provided in addForeignKey()
  • MySQL and SQLite adapters now use the pattern {table}_{columns} (matching PostgresAdapter and SqlserverAdapter behavior)

This fixes an issue where unnamed constraints could cause problems with CakePHP's ConnectionHelper::dropTables() which expects string constraint names. When no name was provided, MySQL would auto-generate one, but the schema reflection could store it with integer array keys, causing TypeError in TableSchema::getConstraint().

Fixes #1040

@dereuromark dereuromark added the bug label Mar 8, 2026
@dereuromark dereuromark force-pushed the fix-auto-generate-fk-constraint-name branch 2 times, most recently from c582b85 to 809abc9 Compare March 8, 2026 20:35
When a foreign key is added without an explicit name, the MysqlAdapter
and SqliteAdapter now generate a name following the pattern
'tablename_columnname' (e.g., 'articles_user_id' for a FK on the
user_id column in the articles table).

This matches the behavior of PostgresAdapter and SqlserverAdapter,
which already auto-generate FK names. This ensures constraint names
are always strings and prevents issues with constraint lookup methods
that expect string names.
Update the expected FK names in comparison files and schema dumps
to match the new auto-generated naming pattern (tablename_columnname).
@dereuromark dereuromark force-pushed the fix-auto-generate-fk-constraint-name branch from ed2b2d3 to 629c85e Compare March 8, 2026 21:02
The FK constraint name change from auto-generated (ibfk_N) to
explicit (table_column) also affects the implicit index MySQL
creates for FKs. Update comparison files to reflect the index
rename from user_id to articles_user_id.
With the FK naming changes, both the lock file and database have
the index named articles_user_id, so no diff is needed for this
index. Remove the index rename operations that were incorrectly
added.
@dereuromark
Copy link
Member Author

Updated PR #1042 with database-specific limits:

  • MySQL: 61 chars (64 - 3)
  • PostgreSQL: 60 chars (63 - 3)
  • SQL Server: 125 chars (128 - 3)
  • SQLite: No limit

Copy link
Member

@markstory markstory left a comment

Choose a reason for hiding this comment

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

Changing the name of indexes, will change the schema created by a migration history. What used to be automatically named by the database engine will now be given a different name by migrations which could cause index add, index drop/change operations to fail as the name of an index has changed.

I don't think we have a good solution for this, but it should be something we point out in the release notes as a potential upgrade issue.

@dereuromark
Copy link
Member Author

dereuromark commented Mar 9, 2026

After the merge of this and follow up, maybe I can invest some time into shimming possibilities?
Like if it doesnt find by name, maybe looking up by fields and see which one would likely match the most?
This could potentially mitigate of those issues.

  // Pseudocode for dropForeignKey fallback                                                                
  $fk = $this->findForeignKeyByName($name);                                                                
  if (!$fk) {                                                                                              
      $fk = $this->findForeignKeyByColumns($columns);                                                      
      // Log warning about name mismatch                                                                   
  }                                                                                                        

But that would only work if we can reverse engineer the columns from the up() statement.

* Add conflict resolution for auto-generated FK constraint names

When auto-generating FK constraint names, check if the name already
exists and append a counter suffix (_2, _3, etc.) if needed.

This prevents duplicate constraint name errors when multiple FKs
are created on the same columns with different references.

* Remove unused variable

* Truncate FK constraint names to max 128 characters

Limit auto-generated foreign key constraint names to 125 characters
to ensure the final name (including potential _XX counter suffix)
stays within 128 characters. This prevents identifier length errors
on databases with strict limits (MySQL: 64, PostgreSQL: 63).

* Use database-specific identifier length limits

- MySQL: 61 chars (64 limit - 3 for _XX suffix)
- PostgreSQL: 60 chars (63 limit - 3 for _XX suffix)
- SQL Server: 125 chars (128 limit - 3 for _XX suffix)
- SQLite: No limit needed

* Use IDENTIFIER_MAX_LENGTH class constant for clarity

Each adapter now defines its database-specific identifier length limit
as a class constant, making the code more self-documenting.
@dereuromark
Copy link
Member Author

All good?

@jamisonbryant jamisonbryant self-requested a review March 11, 2026 19:28
Copy link
Contributor

@jamisonbryant jamisonbryant left a comment

Choose a reason for hiding this comment

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

Looks good, should we update the docs and the migration guide? Changing the conventional format for naming foreign keys feels like something we should warn users about.

dereuromark added a commit that referenced this pull request Mar 11, 2026
Add upgrade documentation explaining the new auto-generated FK constraint
naming behavior introduced in #1041 and #1042, including:
- New consistent naming pattern across all adapters
- Potential impact on existing migrations with rollbacks
- Conflict resolution with counter suffixes
- Database-specific name length limits
@dereuromark
Copy link
Member Author

https://github.com/cakephp/migrations/pull/1049/changes is the follow up then.

@dereuromark dereuromark merged commit 2f52459 into 5.x Mar 11, 2026
14 checks passed
@dereuromark dereuromark deleted the fix-auto-generate-fk-constraint-name branch March 11, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

addForeignkey() without a constraint/name creates a constraint, which has a integer name

3 participants