Skip to content

Auto-generate check constraint name when name is empty#1098

Merged
markstory merged 1 commit into
5.xfrom
fix-check-constraint-auto-name
Jul 5, 2026
Merged

Auto-generate check constraint name when name is empty#1098
markstory merged 1 commit into
5.xfrom
fix-check-constraint-auto-name

Conversation

@dereuromark

@dereuromark dereuromark commented Jul 5, 2026

Copy link
Copy Markdown
Member

Resolves #1097

Problem

Adding a check constraint without an explicit name generates invalid SQL. On PostgreSQL:

$this->table('inventory')
    ->addColumn('quantity', 'integer')
    ->addCheckConstraint('quantity >= 0')
    ->create();

emits an empty constraint name:

ALTER TABLE "public"."inventory" ADD CONSTRAINT  CHECK (quantity >= 0);

which PostgreSQL rejects with SQLSTATE[42601]: Syntax error at or near "CHECK".

Root cause

AddCheckConstraint::build() defaults a missing name to an empty string ($options['name'] ?? ''), but every adapter only auto-generates a name when it is null:

$constraintName = $checkConstraint->getName();
if ($constraintName === null) { /* generate */ }

Since Cake\Database\Schema\Constraint types the name as a non-nullable string, getName() never returns null. The auto-generation branch was therefore dead code and an unnamed constraint kept its empty name.

This has been latent since the constraint value object switched to the core CheckConstraint (non-nullable name) in 5.0, and became user-visible once the fluent Table::addCheckConstraint() API landed in 5.1, which is the first path that lets a name go unset.

The same dead check exists in the Postgres, MySQL and SQLite adapters. SQL Server already throws BadMethodCallException for check constraints, so it is unaffected.

Fix

Treat an empty string like null in all three adapters so a name is generated:

if ($constraintName === null || $constraintName === '') { /* generate */ }

Tests

  • New testAddCheckConstraintAutoGeneratesName() for the Postgres and SQLite adapters covering the empty-name path (SQLite fails without the fix - the empty quoted identifier is a syntax error).
  • Tightened the existing MySQL testAddCheckConstraintWithAutoGeneratedName() to assert the exact generated name. It previously passed even with the bug because the database supplied its own fallback name (check_table2_chk_1 on MySQL, CONSTRAINT_1 on MariaDB); it now asserts migrations supplies the name explicitly on both.

`AddCheckConstraint::build()` defaults a missing name to an empty string,
but the adapters only auto-generated a name when it was `null`. Since
`Cake\Database\Schema\Constraint` types the name as a non-nullable string,
`getName()` never returns `null`, so the auto-generation branch was dead
code and an unnamed check constraint produced invalid SQL, e.g.
`ADD CONSTRAINT  CHECK (...)` which PostgreSQL rejects with
`SQLSTATE[42601]: Syntax error at or near "CHECK"`.

Treat an empty string the same as `null` in the Postgres, MySQL and SQLite
adapters so a name is generated. Add regression tests for the empty-name
path and tighten the MySQL/MariaDB expectation now that migrations supplies
the generated name explicitly instead of relying on the database fallback.
@dereuromark dereuromark added the bug label Jul 5, 2026
@dereuromark dereuromark requested a review from markstory July 5, 2026 10:13
@markstory markstory merged commit ab5e25e into 5.x Jul 5, 2026
14 checks passed
@markstory markstory deleted the fix-check-constraint-auto-name branch July 5, 2026 16:39
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.

Auto-generated constraint names

2 participants