dbal: [2.10.0] Do not add CHARACTER SET for some column types
Bug Report
Q | A |
---|---|
BC Break | no |
Version | 2.10.0 |
Summary
I use Laravel and when composer did the update from 2.9.2 to 2.10.0 our CI broke
Current behaviour
Generate:
ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci
How to reproduce
Using Laravel
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AlterMyColName extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('xxxx', function (Blueprint $table) {
$table->integer('mycolName')->unsigned()->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('xxxx', function (Blueprint $table) {
$table->string('mycolName')->nullable()->change();
});
}
}
Expected behaviour
Do not ADD CHARACTER SET
Generate:
ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED DEFAULT NULL COLLATE `utf8mb4_unicode_ci
More
Introduced by : #3418 ?
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`' at line 1 (SQL: ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`)
Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`' at line 1 (SQL: ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`)
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
660| // If an exception occurs when attempting to run a query, we'll format the error
661| // message to include the bindings with SQL, which will make this exception a
662| // lot more helpful to the developer instead of just the database's errors.
663| catch (Exception $e) {
> 664| throw new QueryException(
665| $query, $this->prepareBindings($bindings), $e
666| );
667| }
668|
Exception trace:
1 Doctrine\DBAL\Driver\PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`' at line 1")
vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:63
2 PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`' at line 1")
vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:61
3 PDO::prepare("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`", [])
vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:61
4 Doctrine\DBAL\Driver\PDOConnection::prepare("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`")
vendor/laravel/framework/src/Illuminate/Database/Connection.php:452
5 Illuminate\Database\Connection::Illuminate\Database\{closure}("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`", [])
vendor/laravel/framework/src/Illuminate/Database/Connection.php:657
6 Illuminate\Database\Connection::runQueryCallback("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`", [], Object(Closure))
vendor/laravel/framework/src/Illuminate/Database/Connection.php:624
7 Illuminate\Database\Connection::run("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`", [], Object(Closure))
vendor/laravel/framework/src/Illuminate/Database/Connection.php:459
8 Illuminate\Database\Connection::statement("ALTER TABLE xxxx CHANGE mycolName mycolName INT UNSIGNED CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`")
vendor/laravel/framework/src/Illuminate/Database/Schema/Blueprint.php:97
9 Illuminate\Database\Schema\Blueprint::build(Object(Illuminate\Database\MySqlConnection), Object(Illuminate\Database\Schema\Grammars\MySqlGrammar))
vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php:278
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 33
- Comments: 34 (13 by maintainers)
I solved my errors in the migration files adding
->charset(null)
.My new line now looks like this:
$table->json('column_name')->charset(null)->nullable()->change();
. Finally the errors are gone šOur ci also broke this day with the same issue metioned above while executing:
$table->dateTime('date_of_birth')->change()->nullable()
which was not nullable before mirgrating. Maybe this issue affects more types than just numeric columns. We worked around with explicit version set for dbal to 2.9.2 in composer.json.Taking feedback from:
$table->addColumn('foo', 'string')->setPlatformOption('charset', 'ascii');
should also be reverted when changing column type (by downstream tooling) by calling->setPlatformOption('charset', null);
.Closing here as
invalid
, since, while it is indeed true that DBAL is creatingINT UNSIGNED CHARACTER SET utf8mb4
, it is merely following instructions about the givenColumn
definition.@nicolasbuch IMHO the problem is that the tool youāre using is sending wrong information to DBAL. That should be fixed by such tool.
Folks, Laravel is using DBAL in the wrong way and relying on a bug. Once the bug got fixed this problem started to happen, hence it being invalid.
I really understand your frustration but the message weāre trying to convey here is that itās Laravelās responsibility to generate the correct object to be sent to DBAL.
It seems like https://github.com/laravel/framework/blob/1bbe5528568555d597582fdbec73e31f8a818dbc/src/Illuminate/Database/Schema/Grammars/ChangeColumn.php#L125 is the culprit.
So, please send a PR there to solve this once and for all š
I dont think this issue is invalid.
I have Laravel migration from text to json. It works perfectly in 2.9.3 and 2.10.0 fails. This means that I am stuck with older dbal version.
Doctrine\DBAL\Driver\PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHARACTER SET utf8mb4 NOT NULL, CHANGE name name JSON CHARACTER SET ut' at line 1
Iām just going to happily link these two threads together, so both sides are informed and we can move further. https://github.com/laravel/framework/issues/30539
Sorry Iām not going to contribute directly by merge request, Iām afraid this would result into a terrible mess.
Cheers and thank you!
Same issue with us - Laravel 5.8 & mysql 5.7 and we have a migration from months ago changing a column type to JSON. On DBAL v2.9.2, it was working fine, but upgrading to 2.10, breaks at the loading of this migration (and during phpunit runs since the entire DB is reconstructed)
Experiencing the same issue when trying to change a column data type. Works with doctrine/dbal 2.9.3 but breaks with 2.10.0
https://github.com/laravel/framework/issues/30539 added, just leaving info in both places in case someone is looking for workaround that do not involve raw statements
As mentioned above, we need this to be laid out in DBAL API only (no laravel) to identify the issue.
By using
->charset(null)
, my error is not solved; but after using->charset('')->collation('')
, the error is gone. For example:$table->integer('resource_type')->default(0)->charset('')->collation('')->change();
FYI this appears to have been resolved in laravel 6 and 7 https://github.com/laravel/framework/issues/30539#issuecomment-622082778
Iām in the same situation as @anususmi (
Laravel
5.7.22 &doctrine/dbal
^2.10) and the issue is still present even with the->charset(null)
workaround š¢Guessing the only way to resolve this is to downgrade?
I do confirm the issue still exists in Laravel 6.x and that is pretty confusing š :
When I was trying to refresh my migrations I got stuck with the following error:
which was caused by the following piece of code:
Previously I did not have any issues and I havenāt made any changes to migrations since the last time they successfully run
The workaround suggested by @stevenbuehner
->charset(null)
solved the problem and I was able to run my migrations againTechnically, not really. You can always use
unprepared
to work this around if you donāt want to get stuck.Thank you @AlterTable for the explanation.
In order to make the proper decision, we need a scenario that reproduces the issue using only the DBAL API.
When generating alter table SQL by Laravel migration, the column diff is calculated as Laravel Blueprint describes:
https://github.com/illuminate/database/blob/e0d5ca153f0204c5312465109246bcf03b7fa603/Schema/Grammars/ChangeColumn.php#L105-L107
https://github.com/illuminate/database/blob/e0d5ca153f0204c5312465109246bcf03b7fa603/Schema/Grammars/ChangeColumn.php#L81-L90
Now see the bugged migration, The Blueprint
$table->integer('mycolName')->unsigned()->nullable()->change();
said one column named āmycolNameā should be changed to unsigned integer, thatās OK. But when itās original type was varchar/text, there is a implicit change: the charset definition should be removed. Neither Laravel nor Doctrine handled this.I think there are two ways to fix this, one is add extra checks in \Doctrine\DBAL\Schema\Table::changeColumn, another is modify Laravel migrate, add checks after changed attributes are set. I prefer the second one.
Not really a BC break, but rather a regression.
still present in: āphpā: ā^7.2ā, ālaravel/frameworkā: ā^6.0ā, ādoctrine/dbalā: ā^2.10ā,
error while trying to change column from text to blob
workaround for me was to make a intermediary migration that runs above the alter and drop the column and recreate it for both fwd and reverse migration
$table->json(ācolumn_nameā)->charset(null)->nullable()->change(); is not working for meā¦!!! I want to add nullable to already existing column $table->string(āphone_numberā); My laravel version 5.7 and doctrine/dbal ^2.10 Please help meā¦!! Thanks in advance š