[HttpFoundation] Fix PdoSessionHandler charset-collation mismatch with the Doctrine DBAL #63137
+3
−4
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Symfony version(s) affected
6.4 (and likely all versions since
configureSchema()was introduced)Description
Using the
PdoSessionHandlerwith MySQL via the Doctrine DBAL and runningmake:migrationresult in an invalid migration under some conditions:This occurs — in particular — because
PdoSessionHandler::configureSchema()sets the collation toutf8mb4_binbut does not set the correspondingcharsettable option.How to reproduce
Configure the Doctrine DBAL with
charset: utf8(or leave it unset in DBAL 3.x):Configure
PdoSessionHandlerfor session storage:Run
php bin/console make:migrationInspect the generated migration — it contains an incompatible charset-collation combination:
Run
php bin/console doctrine:migrations:migrateObserve the failure in migration with the aforementioned charset-collation mismatch error.
Root Cause Analysis
In
PdoSessionHandler::configureSchema():The method sets
collatebut notcharset.The
utf8mb4_bincollation is bound to theutf8mb4character set: no other character set produces a valid MySQL statement. While one might aim for generality and/or optimality by omitting the charset and letting MySQL infer it from the collation, the Doctrine DBAL may supply a charset from its configuration hierarchy, producing an invalid combination like:DEFAULT CHARACTER SET utf8 COLLATE utf8mb4_binCharset Resolution Hierarchy
When building table options, the Doctrine DBAL resolves the charset in this order (the lower the rank, the higher the precedence):
$table->addOption('charset', ...)configureSchema())doctrine.dbal.default_table_options.charsetdoctrine.dbal.charsetdefaultTableOptionsbyAbstractSchemaManager::createSchemaConfig())'utf8'Behavior Matrix: The Doctrine DBAL 3.x
In DBAL 3.x, if no charset is configured at any level, the hardcoded default
'utf8'is used and aDEFAULT CHARACTER SETclause is always emitted.dbal.charsetdefault_table_options.charsetcharset?utf8(hardcoded)utf8mb4_binutf8mb4)utf8mb4utf8mb4_binutf8mb4utf8mb4utf8mb4_binutf8mb4utf8mb4utf8mb4_binutf8utf8(copied)utf8mb4_binutf8utf8mb4)utf8mb4utf8mb4_binutf8utf8mb4utf8mb4utf8mb4_binutf8utf8mb4utf8mb4utf8mb4_binutf8mb4utf8mb4(copied)utf8mb4_binutf8mb4utf8mb4utf8mb4_binBehavior Matrix: The Doctrine DBAL 4.x
In DBAL 4.x, the hardcoded
'utf8'default was removed. If no charset is configured at any level, noDEFAULT CHARACTER SETclause is emitted, allowing MySQL to infer the charset from the collation.dbal.charsetdefault_table_options.charsetcharset?utf8mb4_binutf8mb4)utf8mb4utf8mb4_binutf8mb4utf8mb4utf8mb4_binutf8mb4utf8mb4utf8mb4_binutf8utf8(copied)utf8mb4_binutf8utf8mb4)utf8mb4utf8mb4_binutf8utf8mb4utf8mb4utf8mb4_binutf8utf8mb4utf8mb4utf8mb4_binutf8mb4utf8mb4(copied)utf8mb4_binutf8mb4utf8mb4utf8mb4_binSummary
Proposed Solution
Since
utf8mb4_binis bound toutf8mb4, explicitly setting the charset ensures valid MySQL in all cases:Workarounds
Users can work around this by either:
Configuring
default_table_optionsin the Doctrine DBAL to set a compatible charset:Manually editing the generated migration to change the charset to
utf8mb4Using
$handler->createTable()directly instead ofmake:migration(this method uses raw SQL and lets MySQL infer the charset from the collation)Related Issues
Additional Context
utf8mb4charset has been the recommended MySQL default since MySQL 5.5.3 (2010) and is required for full Unicode support (including emojis).COLLATE utf8mb4_binbut does not mention the Doctrine charset requirement.createTable()method inPdoSessionHandleruses raw SQL (COLLATE utf8mb4_binwithout explicitCHARACTER SET) and works correctly because MySQL infers the charset. TheconfigureSchema()method, however, goes through the Doctrine DBAL which may add an explicitCHARACTER SETclause.