cakephp / cakephp/migrations

Column 'encoding' option is silently ignored for all types except enum/set

Open
#1,113 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
134
Forks
122
Avg merge
2d 2h
Merged PRs (30d)
3

Description

This is a (multiple allowed):

  • bug

  • enhancement

  • feature-discussion (RFC)

  • CakePHP Version: 5.4.1

  • Migrations plugin version: 5.2.6 (present since 5.0.0)

  • Bake plugin version (if relevant): n/a

  • Database server: MariaDB 10.11.14 (applies to MySQL as well)

  • PHP Version: 8.2.33

  • Platform / OS: Linux

What you did

Ran a migration that sets the encoding option on a column, without a collation:

public function up(): void
{
    $this->table('requests')
        ->changeColumn('data', 'text', ['encoding' => 'ascii'])
        ->update();
}
Expected Behavior

The column is created in the ascii character set. The option is documented as supported in columns-and-table-operations.md:

MySQL also supports collation and encoding.

`data` TEXT CHARACTER SET ascii NOT NULL
Actual Behavior

The option is discarded. The generated definition carries no character set, so the column keeps the table default, and no error or warning is raised:

`data` TEXT NOT NULL

All three paths that render a column definition are affected, since each one goes through MysqlAdapter::columnDefinitionSql(). Reading back information_schema.COLUMNS.CHARACTER_SET_NAME on a utf8mb4 table, with ['encoding' => 'ascii'] on every column:

Path Expected Actual
CREATE TABLE ascii utf8mb4
ALTER TABLE ... ADD (addColumn) ascii utf8mb4
ALTER TABLE ... CHANGE (changeColumn) ascii utf8mb4
Why it has gone unnoticed

A migration that pairs encoding with a collation still produces the right column, because MySQL infers the character set from the collation. Only encoding on its own silently does nothing — which is also why no existing test covers it.

Where the option is lost

Column::getValidOptions() accepts encoding, and Table::getChangedColumnOptions() goes as far as preserving it across a changeColumn when it is not passed explicitly. From there:

  • Column::toArray() exports 'collate' and no character-set key.
  • MysqlSchemaDialect::columnDefinitionSql() in cakephp/database renders COLLATE, but has no per-column CHARACTER SET — only the table-level DEFAULT CHARSET.
  • MysqlAdapter::columnDefinitionSql() emits CHARACTER SET only inside the enum/set backwards-compatibility branch; every other type returns the dialect's output verbatim.
Earliest affected version

5.0.0. That release already had the enum/set-only branch in MysqlAdapter::columnDefinitionSql(). Up to 4.x the adapter was Phinx's, whose getColumnSqlDefinition() appended CHARACTER SET for every column type, so this is a regression introduced by the move to cakephp/database.

Other backends are not affected: PostgreSQL sets its character set per database, and SQL Server and SQLite have no per-column character set either. All three offer only per-column COLLATE, which works.

A fix with tests is proposed in #1112.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with MysqlAdapter::columnDefinitionSql(), then trace Column::toArray() and MysqlSchemaDialect::columnDefinitionSql() to understand where encoding is lost. Review the proposed fix in #1112 and verify coverage for CREATE TABLE, addColumn, and changeColumn using information_schema.COLUMNS. Done means encoding-only columns retain the requested character set without breaking enum/set behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
mariadb, mysql, php
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.