MySqlSchemaManagerTest.php 22.8 KB
Newer Older
1 2
<?php

3
namespace Doctrine\DBAL\Tests\Functional\Schema;
4

Sergei Morozov's avatar
Sergei Morozov committed
5
use DateTime;
6
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
7
use Doctrine\DBAL\Platforms\MySqlPlatform;
8
use Doctrine\DBAL\Schema\Comparator;
9
use Doctrine\DBAL\Schema\Schema;
jeroendedauw's avatar
jeroendedauw committed
10
use Doctrine\DBAL\Schema\Table;
11
use Doctrine\DBAL\Tests\Functional\Schema\MySQL\PointType;
12
use Doctrine\DBAL\Types\BlobType;
13
use Doctrine\DBAL\Types\Type;
14
use Doctrine\DBAL\Types\Types;
15

romanb's avatar
romanb committed
16
class MySqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
17
{
18
    protected function setUp(): void
19 20 21
    {
        parent::setUp();

Sergei Morozov's avatar
Sergei Morozov committed
22 23
        if (Type::hasType('point')) {
            return;
24
        }
Sergei Morozov's avatar
Sergei Morozov committed
25

26 27
        $this->resetSharedConn();

28
        Type::addType('point', PointType::class);
29 30
    }

31
    public function testSwitchPrimaryKeyColumns(): void
32
    {
Sergei Morozov's avatar
Sergei Morozov committed
33
        $tableOld = new Table('switch_primary_key_columns');
34 35 36
        $tableOld->addColumn('foo_id', 'integer');
        $tableOld->addColumn('bar_id', 'integer');

Sergei Morozov's avatar
Sergei Morozov committed
37 38
        $this->schemaManager->createTable($tableOld);
        $tableFetched = $this->schemaManager->listTableDetails('switch_primary_key_columns');
Sergei Morozov's avatar
Sergei Morozov committed
39 40
        $tableNew     = clone $tableFetched;
        $tableNew->setPrimaryKey(['bar_id', 'foo_id']);
41

Sergei Morozov's avatar
Sergei Morozov committed
42
        $comparator = new Comparator();
Sergei Morozov's avatar
Sergei Morozov committed
43
        $this->schemaManager->alterTable($comparator->diffTable($tableFetched, $tableNew));
Luís Cobucci's avatar
Luís Cobucci committed
44

Sergei Morozov's avatar
Sergei Morozov committed
45
        $table      = $this->schemaManager->listTableDetails('switch_primary_key_columns');
Luís Cobucci's avatar
Luís Cobucci committed
46 47 48 49 50
        $primaryKey = $table->getPrimaryKeyColumns();

        self::assertCount(2, $primaryKey);
        self::assertContains('bar_id', $primaryKey);
        self::assertContains('foo_id', $primaryKey);
51 52
    }

53
    public function testDiffTableBug(): void
54 55
    {
        $schema = new Schema();
Sergei Morozov's avatar
Sergei Morozov committed
56
        $table  = $schema->createTable('diffbug_routing_translations');
57 58 59 60 61 62
        $table->addColumn('id', 'integer');
        $table->addColumn('route', 'string');
        $table->addColumn('locale', 'string');
        $table->addColumn('attribute', 'string');
        $table->addColumn('localized_value', 'string');
        $table->addColumn('original_value', 'string');
Sergei Morozov's avatar
Sergei Morozov committed
63 64 65
        $table->setPrimaryKey(['id']);
        $table->addUniqueIndex(['route', 'locale', 'attribute']);
        $table->addIndex(['localized_value']); // this is much more selective than the unique index
66

Sergei Morozov's avatar
Sergei Morozov committed
67 68
        $this->schemaManager->createTable($table);
        $tableFetched = $this->schemaManager->listTableDetails('diffbug_routing_translations');
69

Sergei Morozov's avatar
Sergei Morozov committed
70 71
        $comparator = new Comparator();
        $diff       = $comparator->diffTable($tableFetched, $table);
72

Sergei Morozov's avatar
Sergei Morozov committed
73
        self::assertFalse($diff, 'no changes expected.');
74
    }
75

76
    public function testFulltextIndex(): void
77 78 79
    {
        $table = new Table('fulltext_index');
        $table->addColumn('text', 'text');
Sergei Morozov's avatar
Sergei Morozov committed
80
        $table->addIndex(['text'], 'f_index');
81 82 83 84 85
        $table->addOption('engine', 'MyISAM');

        $index = $table->getIndex('f_index');
        $index->addFlag('fulltext');

Sergei Morozov's avatar
Sergei Morozov committed
86
        $this->schemaManager->dropAndCreateTable($table);
87

Sergei Morozov's avatar
Sergei Morozov committed
88
        $indexes = $this->schemaManager->listTableIndexes('fulltext_index');
89 90
        self::assertArrayHasKey('f_index', $indexes);
        self::assertTrue($indexes['f_index']->hasFlag('fulltext'));
91
    }
92

93
    public function testSpatialIndex(): void
94 95 96
    {
        $table = new Table('spatial_index');
        $table->addColumn('point', 'point');
Sergei Morozov's avatar
Sergei Morozov committed
97
        $table->addIndex(['point'], 's_index');
98 99 100 101 102
        $table->addOption('engine', 'MyISAM');

        $index = $table->getIndex('s_index');
        $index->addFlag('spatial');

Sergei Morozov's avatar
Sergei Morozov committed
103
        $this->schemaManager->dropAndCreateTable($table);
104

Sergei Morozov's avatar
Sergei Morozov committed
105
        $indexes = $this->schemaManager->listTableIndexes('spatial_index');
106 107
        self::assertArrayHasKey('s_index', $indexes);
        self::assertTrue($indexes['s_index']->hasFlag('spatial'));
108 109
    }

110
    public function testIndexWithLength(): void
111 112 113 114 115 116 117 118 119 120 121 122
    {
        $table = new Table('index_length');
        $table->addColumn('text', 'string', ['length' => 255]);
        $table->addIndex(['text'], 'text_index', [], ['lengths' => [128]]);

        $this->schemaManager->dropAndCreateTable($table);

        $indexes = $this->schemaManager->listTableIndexes('index_length');
        self::assertArrayHasKey('text_index', $indexes);
        self::assertSame([128], $indexes['text_index']->getOption('lengths'));
    }

123
    public function testAlterTableAddPrimaryKey(): void
124 125 126 127
    {
        $table = new Table('alter_table_add_pk');
        $table->addColumn('id', 'integer');
        $table->addColumn('foo', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
128
        $table->addIndex(['id'], 'idx_id');
129

Sergei Morozov's avatar
Sergei Morozov committed
130
        $this->schemaManager->createTable($table);
131 132 133 134 135

        $comparator = new Comparator();
        $diffTable  = clone $table;

        $diffTable->dropIndex('idx_id');
Sergei Morozov's avatar
Sergei Morozov committed
136
        $diffTable->setPrimaryKey(['id']);
137

Sergei Morozov's avatar
Sergei Morozov committed
138
        $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable));
139

Sergei Morozov's avatar
Sergei Morozov committed
140
        $table = $this->schemaManager->listTableDetails('alter_table_add_pk');
141

142 143
        self::assertFalse($table->hasIndex('idx_id'));
        self::assertTrue($table->hasPrimaryKey());
144
    }
145

146
    public function testDropPrimaryKeyWithAutoincrementColumn(): void
147
    {
Sergei Morozov's avatar
Sergei Morozov committed
148 149
        $table = new Table('drop_primary_key');
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
150
        $table->addColumn('foo', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
151
        $table->setPrimaryKey(['id', 'foo']);
152

Sergei Morozov's avatar
Sergei Morozov committed
153
        $this->schemaManager->dropAndCreateTable($table);
154 155 156 157 158 159 160

        $diffTable = clone $table;

        $diffTable->dropPrimaryKey();

        $comparator = new Comparator();

Sergei Morozov's avatar
Sergei Morozov committed
161
        $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable));
Steve Müller's avatar
Steve Müller committed
162

Sergei Morozov's avatar
Sergei Morozov committed
163
        $table = $this->schemaManager->listTableDetails('drop_primary_key');
Steve Müller's avatar
Steve Müller committed
164

165 166
        self::assertFalse($table->hasPrimaryKey());
        self::assertFalse($table->getColumn('id')->getAutoincrement());
167
    }
168

169
    public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes(): void
170
    {
Sergei Morozov's avatar
Sergei Morozov committed
171
        if ($this->schemaManager->getDatabasePlatform() instanceof MariaDb1027Platform) {
172
            self::markTestSkipped(
belgattitude's avatar
belgattitude committed
173 174
                'MariaDb102Platform supports default values for BLOB and TEXT columns and will propagate values'
            );
175 176
        }

Sergei Morozov's avatar
Sergei Morozov committed
177
        $table = new Table('text_blob_default_value');
178 179 180 181
        $table->addColumn('def_text', 'text', ['default' => 'def']);
        $table->addColumn('def_text_null', 'text', ['notnull' => false, 'default' => 'def']);
        $table->addColumn('def_blob', 'blob', ['default' => 'def']);
        $table->addColumn('def_blob_null', 'blob', ['notnull' => false, 'default' => 'def']);
182

Sergei Morozov's avatar
Sergei Morozov committed
183
        $this->schemaManager->dropAndCreateTable($table);
184

Sergei Morozov's avatar
Sergei Morozov committed
185
        $onlineTable = $this->schemaManager->listTableDetails('text_blob_default_value');
186

187 188 189 190 191 192
        self::assertNull($onlineTable->getColumn('def_text')->getDefault());
        self::assertNull($onlineTable->getColumn('def_text_null')->getDefault());
        self::assertFalse($onlineTable->getColumn('def_text_null')->getNotnull());
        self::assertNull($onlineTable->getColumn('def_blob')->getDefault());
        self::assertNull($onlineTable->getColumn('def_blob_null')->getDefault());
        self::assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull());
193 194 195

        $comparator = new Comparator();

Sergei Morozov's avatar
Sergei Morozov committed
196
        $this->schemaManager->alterTable($comparator->diffTable($table, $onlineTable));
197

Sergei Morozov's avatar
Sergei Morozov committed
198
        $onlineTable = $this->schemaManager->listTableDetails('text_blob_default_value');
199

200 201 202 203 204 205
        self::assertNull($onlineTable->getColumn('def_text')->getDefault());
        self::assertNull($onlineTable->getColumn('def_text_null')->getDefault());
        self::assertFalse($onlineTable->getColumn('def_text_null')->getNotnull());
        self::assertNull($onlineTable->getColumn('def_blob')->getDefault());
        self::assertNull($onlineTable->getColumn('def_blob_null')->getDefault());
        self::assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull());
206
    }
207

208
    public function testColumnCharset(): void
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    {
        $table = new Table('test_column_charset');
        $table->addColumn('id', 'integer');
        $table->addColumn('no_charset', 'text');
        $table->addColumn('foo', 'text')->setPlatformOption('charset', 'ascii');
        $table->addColumn('bar', 'text')->setPlatformOption('charset', 'latin1');
        $this->schemaManager->dropAndCreateTable($table);

        $columns = $this->schemaManager->listTableColumns('test_column_charset');

        self::assertFalse($columns['id']->hasPlatformOption('charset'));
        self::assertEquals('utf8', $columns['no_charset']->getPlatformOption('charset'));
        self::assertEquals('ascii', $columns['foo']->getPlatformOption('charset'));
        self::assertEquals('latin1', $columns['bar']->getPlatformOption('charset'));
    }

225
    public function testAlterColumnCharset(): void
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    {
        $tableName = 'test_alter_column_charset';

        $table = new Table($tableName);
        $table->addColumn('col_text', 'text')->setPlatformOption('charset', 'utf8');

        $this->schemaManager->dropAndCreateTable($table);

        $diffTable = clone $table;
        $diffTable->getColumn('col_text')->setPlatformOption('charset', 'ascii');

        $comparator = new Comparator();

        $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable));

        $table = $this->schemaManager->listTableDetails($tableName);

        self::assertEquals('ascii', $table->getColumn('col_text')->getPlatformOption('charset'));
    }

246
    public function testColumnCharsetChange(): void
247 248
    {
        $table = new Table('test_column_charset_change');
Sergei Morozov's avatar
Sergei Morozov committed
249 250 251 252
        $table->addColumn('col_string', 'string')
            ->setLength(100)
            ->setNotnull(true)
            ->setPlatformOption('charset', 'utf8');
253 254 255 256 257 258 259 260

        $diffTable = clone $table;
        $diffTable->getColumn('col_string')->setPlatformOption('charset', 'ascii');

        $fromSchema = new Schema([$table]);
        $toSchema   = new Schema([$diffTable]);

        $diff = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform());
Sergei Morozov's avatar
Sergei Morozov committed
261 262 263 264 265
        self::assertContains(
            'ALTER TABLE test_column_charset_change CHANGE col_string'
                . ' col_string VARCHAR(100) CHARACTER SET ascii NOT NULL',
            $diff
        );
266 267
    }

268
    public function testColumnCollation(): void
269
    {
270
        $table = new Table('test_collation');
271 272 273 274 275 276
        $table->addOption('collate', $collation = 'latin1_swedish_ci');
        $table->addOption('charset', 'latin1');
        $table->addColumn('id', 'integer');
        $table->addColumn('text', 'text');
        $table->addColumn('foo', 'text')->setPlatformOption('collation', 'latin1_swedish_ci');
        $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci');
277
        $table->addColumn('baz', 'text')->setPlatformOption('collation', 'binary');
Sergei Morozov's avatar
Sergei Morozov committed
278
        $this->schemaManager->dropAndCreateTable($table);
279

Sergei Morozov's avatar
Sergei Morozov committed
280
        $columns = $this->schemaManager->listTableColumns('test_collation');
281

282 283 284 285
        self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions());
        self::assertEquals('latin1_swedish_ci', $columns['text']->getPlatformOption('collation'));
        self::assertEquals('latin1_swedish_ci', $columns['foo']->getPlatformOption('collation'));
        self::assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation'));
286
        self::assertInstanceOf(BlobType::class, $columns['baz']->getType());
287
    }
288

289
    public function testListLobTypeColumns(): void
290 291
    {
        $tableName = 'lob_type_columns';
Sergei Morozov's avatar
Sergei Morozov committed
292
        $table     = new Table($tableName);
293

Sergei Morozov's avatar
Sergei Morozov committed
294 295 296
        $table->addColumn('col_tinytext', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TINYTEXT]);
        $table->addColumn('col_text', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TEXT]);
        $table->addColumn('col_mediumtext', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT]);
297 298
        $table->addColumn('col_longtext', 'text');

Sergei Morozov's avatar
Sergei Morozov committed
299 300 301
        $table->addColumn('col_tinyblob', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TINYBLOB]);
        $table->addColumn('col_blob', 'blob', ['length' => MySqlPlatform::LENGTH_LIMIT_BLOB]);
        $table->addColumn('col_mediumblob', 'blob', ['length' => MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB]);
302 303
        $table->addColumn('col_longblob', 'blob');

Sergei Morozov's avatar
Sergei Morozov committed
304
        $this->schemaManager->dropAndCreateTable($table);
305

Sergei Morozov's avatar
Sergei Morozov committed
306
        $platform       = $this->schemaManager->getDatabasePlatform();
307
        $offlineColumns = $table->getColumns();
Sergei Morozov's avatar
Sergei Morozov committed
308
        $onlineColumns  = $this->schemaManager->listTableColumns($tableName);
309

310
        self::assertSame(
311 312 313
            $platform->getClobTypeDeclarationSQL($offlineColumns['col_tinytext']->toArray()),
            $platform->getClobTypeDeclarationSQL($onlineColumns['col_tinytext']->toArray())
        );
314
        self::assertSame(
315 316 317
            $platform->getClobTypeDeclarationSQL($offlineColumns['col_text']->toArray()),
            $platform->getClobTypeDeclarationSQL($onlineColumns['col_text']->toArray())
        );
318
        self::assertSame(
319 320 321
            $platform->getClobTypeDeclarationSQL($offlineColumns['col_mediumtext']->toArray()),
            $platform->getClobTypeDeclarationSQL($onlineColumns['col_mediumtext']->toArray())
        );
322
        self::assertSame(
323 324 325 326
            $platform->getClobTypeDeclarationSQL($offlineColumns['col_longtext']->toArray()),
            $platform->getClobTypeDeclarationSQL($onlineColumns['col_longtext']->toArray())
        );

327
        self::assertSame(
328 329 330
            $platform->getBlobTypeDeclarationSQL($offlineColumns['col_tinyblob']->toArray()),
            $platform->getBlobTypeDeclarationSQL($onlineColumns['col_tinyblob']->toArray())
        );
331
        self::assertSame(
332 333 334
            $platform->getBlobTypeDeclarationSQL($offlineColumns['col_blob']->toArray()),
            $platform->getBlobTypeDeclarationSQL($onlineColumns['col_blob']->toArray())
        );
335
        self::assertSame(
336 337 338
            $platform->getBlobTypeDeclarationSQL($offlineColumns['col_mediumblob']->toArray()),
            $platform->getBlobTypeDeclarationSQL($onlineColumns['col_mediumblob']->toArray())
        );
339
        self::assertSame(
340 341 342 343
            $platform->getBlobTypeDeclarationSQL($offlineColumns['col_longblob']->toArray()),
            $platform->getBlobTypeDeclarationSQL($onlineColumns['col_longblob']->toArray())
        );
    }
344

345
    public function testDiffListGuidTableColumn(): void
346 347 348 349
    {
        $offlineTable = new Table('list_guid_table_column');
        $offlineTable->addColumn('col_guid', 'guid');

Sergei Morozov's avatar
Sergei Morozov committed
350
        $this->schemaManager->dropAndCreateTable($offlineTable);
351

Sergei Morozov's avatar
Sergei Morozov committed
352
        $onlineTable = $this->schemaManager->listTableDetails('list_guid_table_column');
353 354 355

        $comparator = new Comparator();

356
        self::assertFalse(
357
            $comparator->diffTable($offlineTable, $onlineTable),
Sergei Morozov's avatar
Sergei Morozov committed
358
            'No differences should be detected with the offline vs online schema.'
359 360
        );
    }
361

362
    public function testListDecimalTypeColumns(): void
363 364
    {
        $tableName = 'test_list_decimal_columns';
Sergei Morozov's avatar
Sergei Morozov committed
365
        $table     = new Table($tableName);
366 367

        $table->addColumn('col', 'decimal');
Sergei Morozov's avatar
Sergei Morozov committed
368
        $table->addColumn('col_unsigned', 'decimal', ['unsigned' => true]);
369

Sergei Morozov's avatar
Sergei Morozov committed
370
        $this->schemaManager->dropAndCreateTable($table);
371

Sergei Morozov's avatar
Sergei Morozov committed
372
        $columns = $this->schemaManager->listTableColumns($tableName);
373

374 375 376 377
        self::assertArrayHasKey('col', $columns);
        self::assertArrayHasKey('col_unsigned', $columns);
        self::assertFalse($columns['col']->getUnsigned());
        self::assertTrue($columns['col_unsigned']->getUnsigned());
378 379
    }

380
    public function testListFloatTypeColumns(): void
381 382
    {
        $tableName = 'test_list_float_columns';
Sergei Morozov's avatar
Sergei Morozov committed
383
        $table     = new Table($tableName);
384 385

        $table->addColumn('col', 'float');
Sergei Morozov's avatar
Sergei Morozov committed
386
        $table->addColumn('col_unsigned', 'float', ['unsigned' => true]);
387

Sergei Morozov's avatar
Sergei Morozov committed
388
        $this->schemaManager->dropAndCreateTable($table);
389

Sergei Morozov's avatar
Sergei Morozov committed
390
        $columns = $this->schemaManager->listTableColumns($tableName);
391

392 393 394 395
        self::assertArrayHasKey('col', $columns);
        self::assertArrayHasKey('col_unsigned', $columns);
        self::assertFalse($columns['col']->getUnsigned());
        self::assertTrue($columns['col_unsigned']->getUnsigned());
396
    }
397

398
    public function testJsonColumnType(): void
399
    {
400 401
        $table = new Table('test_mysql_json');
        $table->addColumn('col_json', 'json');
Sergei Morozov's avatar
Sergei Morozov committed
402
        $this->schemaManager->dropAndCreateTable($table);
403

Sergei Morozov's avatar
Sergei Morozov committed
404
        $columns = $this->schemaManager->listTableColumns('test_mysql_json');
405

406
        self::assertSame(Types::JSON, $columns['col_json']->getType()->getName());
407
    }
408

409
    public function testColumnDefaultCurrentTimestamp(): void
410
    {
Sergei Morozov's avatar
Sergei Morozov committed
411
        $platform = $this->schemaManager->getDatabasePlatform();
412

Sergei Morozov's avatar
Sergei Morozov committed
413
        $table = new Table('test_column_defaults_current_timestamp');
414

belgattitude's avatar
belgattitude committed
415
        $currentTimeStampSql = $platform->getCurrentTimestampSQL();
416

belgattitude's avatar
belgattitude committed
417 418
        $table->addColumn('col_datetime', 'datetime', ['notnull' => true, 'default' => $currentTimeStampSql]);
        $table->addColumn('col_datetime_nullable', 'datetime', ['default' => $currentTimeStampSql]);
419

Sergei Morozov's avatar
Sergei Morozov committed
420
        $this->schemaManager->dropAndCreateTable($table);
421

Sergei Morozov's avatar
Sergei Morozov committed
422
        $onlineTable = $this->schemaManager->listTableDetails('test_column_defaults_current_timestamp');
belgattitude's avatar
belgattitude committed
423 424
        self::assertSame($currentTimeStampSql, $onlineTable->getColumn('col_datetime')->getDefault());
        self::assertSame($currentTimeStampSql, $onlineTable->getColumn('col_datetime_nullable')->getDefault());
425 426 427

        $comparator = new Comparator();

belgattitude's avatar
belgattitude committed
428
        $diff = $comparator->diffTable($table, $onlineTable);
Sergei Morozov's avatar
Sergei Morozov committed
429
        self::assertFalse($diff, 'Tables should be identical with column defaults.');
belgattitude's avatar
belgattitude committed
430 431
    }

432
    public function testColumnDefaultsAreValid(): void
belgattitude's avatar
belgattitude committed
433
    {
Sergei Morozov's avatar
Sergei Morozov committed
434
        $table = new Table('test_column_defaults_are_valid');
belgattitude's avatar
belgattitude committed
435

Sergei Morozov's avatar
Sergei Morozov committed
436
        $currentTimeStampSql = $this->schemaManager->getDatabasePlatform()->getCurrentTimestampSQL();
belgattitude's avatar
belgattitude committed
437 438 439
        $table->addColumn('col_datetime', 'datetime', ['default' => $currentTimeStampSql]);
        $table->addColumn('col_datetime_null', 'datetime', ['notnull' => false, 'default' => null]);
        $table->addColumn('col_int', 'integer', ['default' => 1]);
440
        $table->addColumn('col_neg_int', 'integer', ['default' => -1]);
belgattitude's avatar
belgattitude committed
441 442 443 444
        $table->addColumn('col_string', 'string', ['default' => 'A']);
        $table->addColumn('col_decimal', 'decimal', ['scale' => 3, 'precision' => 6, 'default' => -2.3]);
        $table->addColumn('col_date', 'date', ['default' => '2012-12-12']);

Sergei Morozov's avatar
Sergei Morozov committed
445
        $this->schemaManager->dropAndCreateTable($table);
belgattitude's avatar
belgattitude committed
446

447
        $this->connection->executeStatement(
Sergei Morozov's avatar
Sergei Morozov committed
448
            'INSERT INTO test_column_defaults_are_valid () VALUES()'
belgattitude's avatar
belgattitude committed
449 450
        );

451
        $row = $this->connection->fetchAssociative(
belgattitude's avatar
belgattitude committed
452 453 454
            'SELECT *, DATEDIFF(CURRENT_TIMESTAMP(), col_datetime) as diff_seconds FROM test_column_defaults_are_valid'
        );

Sergei Morozov's avatar
Sergei Morozov committed
455
        self::assertInstanceOf(DateTime::class, DateTime::createFromFormat('Y-m-d H:i:s', $row['col_datetime']));
belgattitude's avatar
belgattitude committed
456 457
        self::assertNull($row['col_datetime_null']);
        self::assertSame('2012-12-12', $row['col_date']);
458 459 460 461
        self::assertSame('A', $row['col_string']);
        self::assertEquals(1, $row['col_int']);
        self::assertEquals(-1, $row['col_neg_int']);
        self::assertEquals('-2.300', $row['col_decimal']);
belgattitude's avatar
belgattitude committed
462
        self::assertLessThan(5, $row['diff_seconds']);
463 464 465
    }

    /**
466 467 468 469 470 471 472 473
     * MariaDB 10.2+ does support CURRENT_TIME and CURRENT_DATE as
     * column default values for time and date columns.
     * (Not supported on Mysql as of 5.7.19)
     *
     * Note that MariaDB 10.2+, when storing default in information_schema,
     * silently change CURRENT_TIMESTAMP as 'current_timestamp()',
     * CURRENT_TIME as 'currtime()' and CURRENT_DATE as 'currdate()'.
     * This test also ensure proper aliasing to not trigger a table diff.
474
     */
475
    public function testColumnDefaultValuesCurrentTimeAndDate(): void
476
    {
Sergei Morozov's avatar
Sergei Morozov committed
477
        if (! $this->schemaManager->getDatabasePlatform() instanceof MariaDb1027Platform) {
478
            self::markTestSkipped('Only relevant for MariaDb102Platform.');
479 480
        }

Sergei Morozov's avatar
Sergei Morozov committed
481
        $platform = $this->schemaManager->getDatabasePlatform();
482

Sergei Morozov's avatar
Sergei Morozov committed
483
        $table = new Table('test_column_defaults_current_time_and_date');
484

485
        $currentTimestampSql = $platform->getCurrentTimestampSQL();
belgattitude's avatar
belgattitude committed
486 487
        $currentTimeSql      = $platform->getCurrentTimeSQL();
        $currentDateSql      = $platform->getCurrentDateSQL();
488

489 490 491
        $table->addColumn('col_datetime', 'datetime', ['default' => $currentTimestampSql]);
        $table->addColumn('col_date', 'date', ['default' => $currentDateSql]);
        $table->addColumn('col_time', 'time', ['default' => $currentTimeSql]);
492

Sergei Morozov's avatar
Sergei Morozov committed
493
        $this->schemaManager->dropAndCreateTable($table);
494

Sergei Morozov's avatar
Sergei Morozov committed
495
        $onlineTable = $this->schemaManager->listTableDetails('test_column_defaults_current_time_and_date');
496

497
        self::assertSame($currentTimestampSql, $onlineTable->getColumn('col_datetime')->getDefault());
498 499 500 501 502 503
        self::assertSame($currentDateSql, $onlineTable->getColumn('col_date')->getDefault());
        self::assertSame($currentTimeSql, $onlineTable->getColumn('col_time')->getDefault());

        $comparator = new Comparator();

        $diff = $comparator->diffTable($table, $onlineTable);
Sergei Morozov's avatar
Sergei Morozov committed
504
        self::assertFalse($diff, 'Tables should be identical with column defauts time and date.');
505
    }
506

507
    public function testEnsureTableOptionsAreReflectedInMetadata(): void
508
    {
509
        $this->connection->executeStatement('DROP TABLE IF EXISTS test_table_metadata');
510 511 512 513 514 515 516 517 518 519

        $sql = <<<'SQL'
CREATE TABLE test_table_metadata(
  col1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY
)
COLLATE utf8_general_ci
ENGINE InnoDB
ROW_FORMAT COMPRESSED
COMMENT 'This is a test'
AUTO_INCREMENT=42
520
PARTITION BY HASH (col1)
521 522
SQL;

523
        $this->connection->executeStatement($sql);
524 525 526 527 528 529
        $onlineTable = $this->schemaManager->listTableDetails('test_table_metadata');

        self::assertEquals('InnoDB', $onlineTable->getOption('engine'));
        self::assertEquals('utf8_general_ci', $onlineTable->getOption('collation'));
        self::assertEquals(42, $onlineTable->getOption('autoincrement'));
        self::assertEquals('This is a test', $onlineTable->getOption('comment'));
530 531 532 533
        self::assertEquals([
            'row_format' => 'COMPRESSED',
            'partitioned' => true,
        ], $onlineTable->getOption('create_options'));
534 535
    }

536
    public function testEnsureTableWithoutOptionsAreReflectedInMetadata(): void
537
    {
538
        $this->connection->executeStatement('DROP TABLE IF EXISTS test_table_empty_metadata');
539

540
        $this->connection->executeStatement('CREATE TABLE test_table_empty_metadata(col1 INT NOT NULL)');
541 542 543 544 545 546 547 548
        $onlineTable = $this->schemaManager->listTableDetails('test_table_empty_metadata');

        self::assertNotEmpty($onlineTable->getOption('engine'));
        // collation could be set to default or not set, information_schema indicate a possibly null value
        self::assertFalse($onlineTable->hasOption('autoincrement'));
        self::assertEquals('', $onlineTable->getOption('comment'));
        self::assertEquals([], $onlineTable->getOption('create_options'));
    }
549

550
    public function testParseNullCreateOptions(): void
551 552 553 554 555
    {
        $table = $this->schemaManager->listTableDetails('sys.processlist');

        self::assertEquals([], $table->getOption('create_options'));
    }
556
}