简体   繁体   中英

Laravel Migration rename nullable field workaround?

It appear there is a breaking change in mariadb 10.2.7 if you try to rename a field nullable datetime column and you will get an error if you run a migration:

[Illuminate\Database\QueryException]
  SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'due_date' (SQL: ALTER TABLE test
   CHANGE dueDate due_date DATETIME DEFAULT 'NULL')

Create migration:

class CreateTestTable extends Migration
{
    public function up()
    {
        Schema::create('test', function (Blueprint $table) {
            $table->increments('id');
            $table->dateTime('dueDate')->nullable();
        });
    }
}

Create a second migration to rename the column:

class RenameColumn extends Migration
{
    public function up()
    {
        Schema::table('test', function(Blueprint $table) {
            $table->renameColumn('dueDate', 'due_date');
        });
    }
}

Is there a workaround to get this to work?

According to doctrine/dbal issue :

In order to allow expressions as default values and distinguish them from literals, Mariadb now quotes default values in information_schema.column table. This changes brings a lot of incompatibilities between the (Oracle-)Mysql/MariaDB platforms.

Instead of creating a specific SchemaManager for MariaDB, the solution taken in this P/R is to map the introduced changes in the current MySQLSchemaManager (method: getMariaDb1027ColumnDefault()).

From MariaDB 10.2.7, information schema changes includes:

NULL is now quoted as 'NULL' (exception when colum default is not nullable and no default provided: NULL is saved in information_schema), EDIT: see an exception https://jira.mariadb.org/browse/MDEV-14053 String defaults are quoted (To save the string 'NULL', set the default as ''NULL''). Escaping: "'" are silently changed to "''" in information schema. This should not have impact unless you manually escaped default values with "'" in your models (schema diff). See also point 5. Default literals values must be quoted which brings support for automatic CURRENT_TIMESTAMP, CURRENT_DATE, CURRENT_TIME defaults are silently changed to 'current_timestamp()', 'currdate()', 'currtime()'. To prevent schema diff, they are mapped back to their original values.

You could try this approach:

Create new column and run query to copy values from your old column to your new column

class RenameColumn extends Migration
{
    public function up()
    {
        Schema::table('test', function(Blueprint $table){
            $table->dateTime('due_date')->nullable();
        });

        // copy values from column 'dueDate' to 'due_date'
        // DB::update returns number of affected rows
        DB::update('UPDATE `test` SET due_date = dueDate');

        Schema::table('test', function(Blueprint $table){
            $table->dropColumn('dueDate');
        });
    }

    public function down()
    {
        Schema::table('test', function(Blueprint $table){
            $table->dateTime('dueDate')->nullable();
        });

        DB::update('UPDATE `test` SET dueDate = due_date');

        Schema::table('test', function(Blueprint $table){
            $table->dropColumn('due_date');
        });
    }
}

Although the provided solutions work I prefer a simpler approach:

public function up()
{
    Schema::table('test', function (Blueprint $table) {
        DB::statement('ALTER TABLE `test` CHANGE `dueDate` `due_date` TIMESTAMP NULL DEFAULT NULL;');
    });
}

public function down()
{
    Schema::table('test', function (Blueprint $table) {
        DB::statement('ALTER TABLE `test` CHANGE `dueDate` `due_date` TIMESTAMP NULL DEFAULT NULL;');
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM