vvinhas's avatar

[L5] Migration issue

Hey guys

I'm facing a little bit of a trouble here.

I made a new migration to update a column from not null, to null

php artisan make:migration update_foo_table --table foo

... and in my migration file ...

$table->string('bar')->nullable()->change();

Already did as suggested and required the doctrine/dbal (~2.4) package under my composer.json file

The thing is, when I try to migrate, I receive the following error

exception 'Doctrine\DBAL\DBALException' with message 'Unknown column type "varchar(255)" requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database introspection then you might have forgot to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.' in /home/vagrant/code/gestec-nit/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:228

What am I doing wrong?

0 likes
3 replies
bobbybouwmann's avatar

I assume that you're trying to edit a column that you have already added data on, so dropping column and adding again as a nullable column is not possible without losing data. We'll alter the existing column.

Let say you have a migration like this:

Schema::create('users', function(Blueprint $table)
{
    $table->increments('id');
        $table->integer('user_id')->unsigned(); // This field should be nullable
}

However, Laravel's schema builder does not support modifying columns other than renaming the column. So you will need to run raw queries to do them, like this:

function up()
{
        DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

And to make sure you can still rollback your migration, we'll do the down() as well.

function down()
{
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED;');
}

One note is that since you are converting between nullable and not nullable, you'll need to make sure you clean up data before/after your migration. So do that in your migration script both ways:

function up()
{
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE `users` SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down()
{
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
TheFox's avatar

I have the same issue.

[Doctrine\DBAL\DBALException]
Unknown column type "timestamp" requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the known types with \Doctrine\DBA
L\Types\Type::getTypesMap(). If this error occurs during database introspection then you might have forgot to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTy
peMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.

@bobbybouwmann: So you will need to run raw queries to do them, like this:
DB::statement('ALTER TABLE users MODIFY user_id INTEGER UNSIGNED NULL;');

This seems not a safe mothod. How can I do this while using a table name prefix? Maybe there is a function to generate the table name dynamically? Is there any other way to ALTER the table using the schema builder?

Edit:

It seems that you can use DB::getQueryGrammar()->wrapTable($tableName) to get the raw table name including the prefix of your configuration.

Now my migration looks like this:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class ChangeBirthdayToTimestampPersonsTable extends Migration{
    
    public function up(){
        $tableName = DB::getQueryGrammar()->wrapTable('persons');
        
        DB::statement('ALTER TABLE '.$tableName.' CHANGE `birthday` `birthday` TIMESTAMP NULL;');
    }
    
    public function down(){
        $tableName = DB::getQueryGrammar()->wrapTable('persons');
        
        DB::statement('ALTER TABLE '.$tableName.' CHANGE `birthday` `birthday` DATE NULL;');
    }
    
}

So in your case I would use this:

function up(){
    $tableName = DB::getQueryGrammar()->wrapTable('users');
    DB::statement('ALTER TABLE '.$tableName.' MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE '.$tableName.' SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down(){
    $tableName = DB::getQueryGrammar()->wrapTable('users');
    DB::statement('UPDATE '.$tableName.' SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE '.$tableName.' MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Please or to participate in this conversation.