Skip to content

bake migration_snapshot drops collation and engine from table definitions #1104

Description

@jamisonbryant

Description

bake migration_snapshot silently drops table level options from the generated $this->table() statement. Only the primary key portion is rendered, so collation and engine are omitted entirely and any database rebuilt from the snapshot loses them.

Table options are already documented and supported on the write path — Creating a Table lists comment, collation, row_format, engine, signed, and limit, and MysqlAdapter::createTable() consumes them. So a user can write a table's collation or engine in a migration, but bake cannot read it back.

Reproduction

Against MySQL, with a database whose default collation is utf8mb4_0900_ai_ci:

CREATE TABLE events (
    id INT NOT NULL AUTO_INCREMENT,
    title VARCHAR(255) NULL,
    PRIMARY KEY (id)
) COLLATE=utf8mb3_hungarian_ci;

CREATE TABLE parts (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
) ENGINE=MyISAM;
bin/cake bake migration_snapshot TableOptionsProof

Expected — the snapshot preserves the options:

$this->table('events', ['collation' => 'utf8_hungarian_ci'])
    ->addColumn('title', 'string', [...])
    ->create();

$this->table('parts', ['engine' => 'MyISAM'])
    ->addColumn('name', 'string', [...])
    ->create();

Actual — both options are missing:

$this->table('events')
    ->addColumn('title', 'string', [...])
    ->create();

$this->table('parts')
    ->addColumn('name', 'string', [...])
    ->create();

Running the generated migration produces events with the database default collation and parts with the InnoDB engine.

Impact

A table whose collation or engine differs from the connection defaults is rebuilt from the snapshot with the connection defaults instead of its real ones.

Snapshots rebuild fresh databases (CI, test, new environments) while existing databases keep their real schema, so the source and the rebuilt database diverge. Collation determines string comparison semantics and index key length.

It makes the snapshot unusable as a migration baseline, which is its primary use case: squashing a long migration history into a snapshot silently rewrites the schema.

Observed in a CakePHP 5.3 / migrations 5.0.0 application on eight tables declared with 'collation' => 'utf8_unicode_ci', which regenerate as utf8mb4_unicode_ci.

Root cause

This is not a reflection gap. The values are present on the TableSchema at bake time — MysqlSchemaDialect::describeOptions() returns engine and collation, and SchemaDialect::describe() applies them via setOptions().

They are dropped at render time. templates/bake/element/create-tables.twig builds the table options array from the primary key alone and never reads TableSchema::getOptions().

Column collation is affected as a consequence: MigrationHelper::attributes() strips a column's collate when it equals the table's collation, which is only sound if the table collation is rendered.

Table options are reflected for MySQL only; the other dialects return [] from describeOptions().

Versions

  • migrations: 5.x
  • CakePHP: 5.3
  • Database: MySQL / MariaDB (table options are only reflected in MysqlSchemaDialect)

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions