Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions src/Driver/MySQL/Schema/MySQLColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class MySQLColumn extends AbstractColumn
*/
public const DATETIME_NOW = 'CURRENT_TIMESTAMP';

public const EXCLUDE_FROM_COMPARE = ['size', 'timezone', 'userType', 'attributes', 'first', 'after'];
public const EXCLUDE_FROM_COMPARE = ['size', 'timezone', 'userType', 'attributes', 'first', 'after', 'unknownSize'];
protected const INTEGER_TYPES = ['tinyint', 'smallint', 'mediumint', 'int', 'bigint'];

protected array $mapping = [
Expand Down Expand Up @@ -162,6 +162,11 @@ class MySQLColumn extends AbstractColumn
)]
protected int $size = 0;

/**
* True if size is not defined in DB schema.
*/
protected bool $unknownSize = false;

/**
* Column is auto incremental.
*/
Expand Down Expand Up @@ -251,6 +256,7 @@ public static function createInstance(string $table, array $schema, ?\DateTimeZo

// since 8.0 database does not provide size for some columns
if ($column->size === 0) {
$column->unknownSize = true;
switch ($column->type) {
case 'int':
$column->size = 11;
Expand Down Expand Up @@ -291,6 +297,12 @@ public static function createInstance(string $table, array $schema, ?\DateTimeZo
return $column;
}

public function size(int $value): self
{
$this->unknownSize = false;
return parent::__call('size', [$value]);
}

/**
* @psalm-return non-empty-string
*/
Expand Down Expand Up @@ -327,10 +339,27 @@ public function sqlStatement(DriverInterface $driver): string

public function compare(AbstractColumn $initial): bool
{
$result = parent::compare($initial);
\assert($initial instanceof self);
$self = $this;

// MySQL 8.0 does not provide size for unsigned integers without zerofill
// so we can get wrong results in comparison of boolean columns
if ($self->unknownSize || $initial->unknownSize) {
// if one of the columns is boolean, we can safely assume that size is 1
if (\in_array($self->userType, ['bool', 'boolean'], true)) {
$initial = clone $initial;
$initial->size = 1;
} elseif (\in_array($initial->userType, ['bool', 'boolean'], true)) {
$self = clone $self;
$self->size = 1;
}
}

$result = \Closure::fromCallable([parent::class, 'compare'])->bindTo($self)($initial);


if ($this->type === 'varchar' || $this->type === 'varbinary') {
return $result && $this->size === $initial->size;
if ($self->type === 'varchar' || $self->type === 'varbinary') {
return $result && $self->size === $initial->size;
}

return $result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,79 @@
class BooleanColumnTest extends CommonClass
{
public const DRIVER = 'mysql';

public function testBooleanDefaultSize(): void
{
$schema = $this->schema('table');
$schema->boolean('column');
$schema->save();

$column = $this->fetchSchema($schema)->column('column');

$this->assertSame('boolean', $column->getAbstractType());
$this->assertSame(1, $column->getSize());
}

public function testBooleanComparisonWithSize(): void
{
$schema = $this->schema('table');
$foo = $schema->boolean('foo')->defaultValue(false)->nullable(false)->unsigned(true)->size(1)->zerofill(true);
$bar = $schema->boolean('bar', nullable: true, unsigned: true, size: 1, zerofill: true);
$baz = $schema->boolean('baz', nullable: false, unsigned: true);
$mux = $schema->boolean('mux', nullable: false);
$schema->save();

$schema = $this->schema('table');
$this->assertTrue($schema->exists());
$this->assertSame(1, $foo->getSize());
$this->assertSame(1, $bar->getSize());
$this->assertSame(1, $baz->getSize());
$this->assertSame(1, $mux->getSize());
$this->assertSame(1, $schema->column('foo')->getSize());
$this->assertSame(1, $schema->column('bar')->getSize());
$this->assertTrue(\in_array($schema->column('baz')->getSize(), [1, 4], true));
$this->assertSame(1, $schema->column('mux')->getSize());
$this->assertTrue($foo->compare($schema->column('foo')));
$this->assertTrue($bar->compare($schema->column('bar')));
$this->assertTrue($baz->compare($schema->column('baz')));
$this->assertTrue($mux->compare($schema->column('mux')));
}

public function testBooleanWithProblematicValues(): void
{
$schema = $this->schema('table');

$column = $schema->boolean('target')
->defaultValue(false)
->nullable(false)
->unsigned(true)
->comment('Target comment');

$schema->save();

$this->assertTrue($schema->exists());

$schema = $this->schema('table');
$target = $schema->column('target');

$this->assertSame(1, $column->getSize());
$this->assertSame(4, $target->getSize());
$this->assertFalse($column->isNullable());
$this->assertFalse($target->isNullable());
$this->assertTrue($column->isUnsigned());
$this->assertTrue($target->isUnsigned());

$object = new \ReflectionObject($target);
$property = $object->getProperty('defaultValue');
$property->setAccessible(true);
$defaultValue = $property->getValue($target);

$this->assertSame(false, $column->getDefaultValue());
$this->assertSame(0, $target->getDefaultValue());
$this->assertSame('0', $defaultValue);
$this->assertTrue($column->compare($target));
$this->assertTrue($target->compare($column));
// The size was not changed
$this->assertSame(4, $target->getSize());
}
}
Loading