Framework: Schema:: normal or bug?

Created on 6 Feb 2015  路  11Comments  路  Source: laravel/framework

code is better than words

/**
* Setup: Laravel 5.0, MySQL driver
**/

// Step 1
Schema::table('test_abcd', function(Blueprint $table)
{
    // Create a double(8,2), not a float
    $table->float('float_test');

    // Create a double
    $table->double('double_test');
});

// Step 2
Schema::table('test_abcd', function(Blueprint $table)
{
   // FATAL Error, see log **1**
   $table->float('float_test', 6, 2)->change();

    // FATAL Error, too
    $table->double('double_test')->change();
});

Log 1

> php.exe X:\xxx\artisan migrate
exception 'Doctrine\DBAL\DBALException' with message 'Unknown column type "double(6, 2)" 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 X:\xxx\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php:228
Stack trace:
#0 X:\xxx\vendor\doctrine\dbal\lib\Doctrine\DBAL\Types\Type.php(172): Doctrine\DBAL\DBALException::unknownColumnType('double(6, 2)')
#1 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Grammars\Grammar.php(361): Doctrine\DBAL\Types\Type::getType('double(6, 2)')
#2 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Grammars\Grammar.php(349): Illuminate\Database\Schema\Grammars\Grammar->getDoctrineColumnChangeOptions(Object(Illuminate\Support\Fluent))
#3 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Grammars\Grammar.php(319): Illuminate\Database\Schema\Grammars\Grammar->getDoctrineColumnForChange(Object(Doctrine\DBAL\Schema\Table), Object(Illuminate\Support\Fluent))
#4 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Grammars\Grammar.php(303): Illuminate\Database\Schema\Grammars\Grammar->getTableWithColumnChanges(Object(Illuminate\Database\Schema\Blueprint), Object(Doctrine\DBAL\Schema\Table))
#5 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Grammars\Grammar.php(282): Illuminate\Database\Schema\Grammars\Grammar->getChangedDiff(Object(Illuminate\Database\Schema\Blueprint), Object(Doctrine\DBAL\Schema\MySqlSchemaManager))
#6 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Blueprint.php(89): Illuminate\Database\Schema\Grammars\Grammar->compileChange(Object(Illuminate\Database\Schema\Blueprint), Object(Illuminate\Support\Fluent), Object(Illuminate\Database\MySqlConnection))
#7 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Blueprint.php(61): Illuminate\Database\Schema\Blueprint->toSql(Object(Illuminate\Database\MySqlConnection), Object(Illuminate\Database\Schema\Grammars\MySqlGrammar))
#8 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Builder.php(169): Illuminate\Database\Schema\Blueprint->build(Object(Illuminate\Database\MySqlConnection), Object(Illuminate\Database\Schema\Grammars\MySqlGrammar))
#9 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Schema\Builder.php(94): Illuminate\Database\Schema\Builder->build(Object(Illuminate\Database\Schema\Blueprint))
#10 X:\xxx\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php(213): Illuminate\Database\Schema\Builder->table('manufacturers', Object(Closure))
#11 X:\xxx\database\migrations\2015_02_06_112008_add_test2_to_manufacturers_table.php(19): Illuminate\Support\Facades\Facade::__callStatic('table', Array)
#12 X:\xxx\database\migrations\2015_02_06_112008_add_test2_to_manufacturers_table.php(19): Illuminate\Support\Facades\Schema::table('manufacturers', Object(Closure))
#13 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Migrations\Migrator.php(135): AddTest2ToManufacturersTable->up()
#14 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Migrations\Migrator.php(111): Illuminate\Database\Migrations\Migrator->runUp('2015_02_06_1120...', 3, false)
#15 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Migrations\Migrator.php(82): Illuminate\Database\Migrations\Migrator->runMigrationList(Array, false)
#16 X:\xxx\vendor\laravel\framework\src\Illuminate\Database\Console\Migrations\MigrateCommand.php(73): Illuminate\Database\Migrations\Migrator->run('X:\xxx...', false)
#17 [internal function]: Illuminate\Database\Console\Migrations\MigrateCommand->fire()
#18 X:\xxx\vendor\laravel\framework\src\Illuminate\Container\Container.php(523): call_user_func_array(Array, Array)
#19 X:\xxx\vendor\laravel\framework\src\Illuminate\Console\Command.php(115): Illuminate\Container\Container->call(Array)
#20 X:\xxx\vendor\symfony\console\Symfony\Component\Console\Command\Command.php(253): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 X:\xxx\vendor\laravel\framework\src\Illuminate\Console\Command.php(101): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 X:\xxx\vendor\symfony\console\Symfony\Component\Console\Application.php(874): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 X:\xxx\vendor\symfony\console\Symfony\Component\Console\Application.php(195): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Database\Console\Migrations\MigrateCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 X:\xxx\vendor\symfony\console\Symfony\Component\Console\Application.php(126): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 X:\xxx\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php(91): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#26 X:\xxx\artisan(34): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#27 {main}

Process finished with exit code 1 at 12:26:41.
Execution time: 505 ms.

According to the documentation it should work

Most helpful comment

@mtaiyabm, try this

use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\Type;

public function up() {
    if (!Type::hasType('double')) {
            Type::addType('double', FloatType::class);
    }

    // ...
}

All 11 comments

It may be worth noting that the decision for a $table->float() to create a double in MySQL databases was a deliberate one by Taylor in September.

IlluminateDatabase\Schema\Grammars\MySqlGrammar#L389

I don't know the exact reasons for this.

As for your fatal on ->change() this obviously shouldn't be happening. Although the documentation doesn't explicitly state that ->change() should be used to change a column type, I see no reason why it shouldn't be used. I will have a dig later unless someone else takes a look first.

+1 I am having strange errors when using ->change() in my migrations.

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/youanden/projects/aws3/ninjagift/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:228

From doing this: $t->string('paykey')->change(); which was a integer type column before.

So I had a closer look at this and there are a number of issues at play here.

For ->change() functionality, doctrine/dbal is utilised to create a diff between your current table definition and the definition created by your calls to ->change() before executing the necessary SQL to bring the diffs inline.

At IlluminateDatabase\Schema\Grammars\Grammar#L361, a Doctrine\DBAL\Types\Type object is instantiated with the illuminate column type. However, ->getType() on an illuminate column (see Illuminate\Schema\Grammars\MySqlGrammar) for certain column types such as a float will return double(3, 5) as opposed to float which is what the DBAL type is expecting. Note that the actual column type is different plus the lack of parameters in the string.

On top of this, the actual comparison diff is generated using Doctrine\DBAL\Schema\Comparator which only checks precision and scale for DecimalType columns, not FloatType columns. So even if the first issue didn't exist and the DBAL type could be instantiated, the diff would come back negative if you had only updated the float precision as in the example from @xeno010.

So in summary, illuminate/database has an issue with types that are incompatible with Doctrine\DBAL\Types\Type and doctrine/dbal has an issue in not checking scale and precision for FloatType column types in the diff comparator.

I will open a pull request with doctrine for the second issue now. However, I don't have enough knowledge around illuminate/database to attempt a PR in that department.

@GrahamCampbell I think it would be a good idea to reopen this issue?

I would suggest renaming to Illuminate Grammar types incompatible with Doctrine DBAL types or something similar.

So it turns out that doctrine/dbal only defines scales and precision for decimal types and doesn't consider them at all for float types (not just in the comparator). This must be for a good reason as it appears to have been a conscious choice.

I'm out of my depth in DBAL land I'm afraid.

Here's hoping that the information above will help towards getting a fix implemented.

bitmoji

It's still happening to me.

Exact same issue here with Laravel 5.6

Will there be any fix for this issue?

@mtaiyabm, try this

use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\Type;

public function up() {
    if (!Type::hasType('double')) {
            Type::addType('double', FloatType::class);
    }

    // ...
}

@LastDragon-ru that allows the data type to be set to double - but when looking at the structure after migrating, the number of digits and precision are both set to 0 even when providing params.

@LastDragon-ru, indeed when I try:
$table->double('price')->nullable()->change();
I get:

Doctrine\DBAL\DBALException : Unknown column type "double" requested.

When I add:

use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\Type;

public function up() {
    if (!Type::hasType('double')) {
            Type::addType('double', FloatType::class);
    }
    Schema::table('product_options', function($table) {         
            $table->double('price', 8, 2)->nullable()->change();
     });
}

It changes the defaults to null, but it does not set the precision.

The only way I was able to change the precision trough migration was with RAW SQL inside the migration. Still it is so awkward that you can define a double column on creation but can't change it to NULLABLE DOUBLE with the ->change(). And this is actually on purpose? I am still headbanging why...

PS: For those wondering how to change double column trough RAW SQL:
ALTER TABLE YourTableNameHere MODIFY COLUMN YourColumnNameHere double(8,2) null

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Fuzzyma picture Fuzzyma  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

PhiloNL picture PhiloNL  路  3Comments

ghost picture ghost  路  3Comments

YannPl picture YannPl  路  3Comments