Failed Conditions
Push — master ( 24dbc4...1eba78 )
by Sergei
31:31 queued 31:22
created

testDropsDatabaseWithActiveConnections()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 18
nc 8
nop 0
dl 0
loc 30
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Tests\Functional\Schema;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\DBAL\DBALException;
9
use Doctrine\DBAL\Driver\Statement;
10
use Doctrine\DBAL\Events;
11
use Doctrine\DBAL\Platforms\OraclePlatform;
12
use Doctrine\DBAL\Schema\AbstractAsset;
13
use Doctrine\DBAL\Schema\AbstractSchemaManager;
14
use Doctrine\DBAL\Schema\Column;
15
use Doctrine\DBAL\Schema\ColumnDiff;
16
use Doctrine\DBAL\Schema\Comparator;
17
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
18
use Doctrine\DBAL\Schema\Index;
19
use Doctrine\DBAL\Schema\SchemaDiff;
20
use Doctrine\DBAL\Schema\Sequence;
21
use Doctrine\DBAL\Schema\Table;
22
use Doctrine\DBAL\Schema\TableDiff;
23
use Doctrine\DBAL\Schema\View;
24
use Doctrine\DBAL\Tests\FunctionalTestCase;
25
use Doctrine\DBAL\Types\BinaryType;
26
use Doctrine\DBAL\Types\DateTimeType;
27
use Doctrine\DBAL\Types\DecimalType;
28
use Doctrine\DBAL\Types\IntegerType;
29
use Doctrine\DBAL\Types\StringType;
30
use Doctrine\DBAL\Types\TextType;
31
use Doctrine\DBAL\Types\Type;
32
use ReflectionMethod;
33
use function array_filter;
34
use function array_keys;
35
use function array_map;
36
use function array_search;
37
use function array_values;
38
use function assert;
39
use function count;
40
use function current;
41
use function end;
42
use function explode;
43
use function in_array;
44
use function is_string;
45
use function sprintf;
46
use function str_replace;
47
use function strcasecmp;
48
use function strtolower;
49
50
abstract class SchemaManagerFunctionalTestCase extends FunctionalTestCase
51
{
52
    /** @var AbstractSchemaManager */
53
    protected $schemaManager;
54
55
    protected function getPlatformName() : string
56
    {
57
        $class     = static::class;
58
        $e         = explode('\\', $class);
59
        $testClass = end($e);
60
        assert(is_string($testClass));
61
62
        return strtolower(str_replace('SchemaManagerTest', '', $testClass));
63
    }
64
65
    protected function setUp() : void
66
    {
67
        parent::setUp();
68
69
        $dbms = $this->getPlatformName();
70
71
        if ($this->connection->getDatabasePlatform()->getName() !== $dbms) {
72
            self::markTestSkipped(static::class . ' requires the use of ' . $dbms);
73
        }
74
75
        $this->schemaManager = $this->connection->getSchemaManager();
76
    }
77
78
    protected function tearDown() : void
79
    {
80
        parent::tearDown();
81
82
        $this->schemaManager->tryMethod('dropTable', 'testschema.my_table_in_namespace');
83
84
        //TODO: SchemaDiff does not drop removed namespaces?
85
        try {
86
            //sql server versions below 2016 do not support 'IF EXISTS' so we have to catch the exception here
87
            $this->connection->exec('DROP SCHEMA testschema');
88
        } catch (DBALException $e) {
89
            return;
90
        }
91
    }
92
93
    /**
94
     * @group DBAL-1220
95
     */
96
    public function testDropsDatabaseWithActiveConnections() : void
97
    {
98
        if (! $this->schemaManager->getDatabasePlatform()->supportsCreateDropDatabase()) {
99
            self::markTestSkipped('Cannot drop Database client side with this Driver.');
100
        }
101
102
        $this->schemaManager->dropAndCreateDatabase('test_drop_database');
103
104
        $knownDatabases = $this->schemaManager->listDatabases();
105
        if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
106
            self::assertContains('TEST_DROP_DATABASE', $knownDatabases);
107
        } else {
108
            self::assertContains('test_drop_database', $knownDatabases);
109
        }
110
111
        $params = $this->connection->getParams();
112
        if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
113
            $params['user'] = 'test_drop_database';
114
        } else {
115
            $params['dbname'] = 'test_drop_database';
116
        }
117
118
        $user     = $params['user'] ?? '';
119
        $password = $params['password'] ?? '';
120
121
        $this->connection->getDriver()->connect($params, $user, $password);
122
123
        $this->schemaManager->dropDatabase('test_drop_database');
124
125
        self::assertNotContains('test_drop_database', $this->schemaManager->listDatabases());
126
    }
127
128
    /**
129
     * @group DBAL-195
130
     */
131
    public function testDropAndCreateSequence() : void
132
    {
133
        $platform = $this->connection->getDatabasePlatform();
134
135
        if (! $platform->supportsSequences()) {
136
            self::markTestSkipped(
137
                sprintf('The "%s" platform does not support sequences.', $platform->getName())
138
            );
139
        }
140
141
        $name = 'dropcreate_sequences_test_seq';
142
143
        $this->schemaManager->dropAndCreateSequence(new Sequence($name, 20, 10));
144
145
        self::assertTrue($this->hasElementWithName($this->schemaManager->listSequences(), $name));
146
    }
147
148
    /**
149
     * @param AbstractAsset[] $items
150
     */
151
    private function hasElementWithName(array $items, string $name) : bool
152
    {
153
        $filteredList = array_filter(
154
            $items,
155
            static function (AbstractAsset $item) use ($name) : bool {
156
                return $item->getShortestName($item->getNamespaceName()) === $name;
157
            }
158
        );
159
160
        return count($filteredList) === 1;
161
    }
162
163
    public function testListSequences() : void
164
    {
165
        $platform = $this->connection->getDatabasePlatform();
166
167
        if (! $platform->supportsSequences()) {
168
            self::markTestSkipped(
169
                sprintf('The "%s" platform does not support sequences.', $platform->getName())
170
            );
171
        }
172
173
        $this->schemaManager->createSequence(
174
            new Sequence('list_sequences_test_seq', 20, 10)
175
        );
176
177
        foreach ($this->schemaManager->listSequences() as $sequence) {
178
            if (strtolower($sequence->getName()) === 'list_sequences_test_seq') {
179
                self::assertSame(20, $sequence->getAllocationSize());
180
                self::assertSame(10, $sequence->getInitialValue());
181
182
                return;
183
            }
184
        }
185
186
        self::fail('Sequence was not found.');
187
    }
188
189
    public function testListDatabases() : void
190
    {
191
        if (! $this->schemaManager->getDatabasePlatform()->supportsCreateDropDatabase()) {
192
            self::markTestSkipped('Cannot drop Database client side with this Driver.');
193
        }
194
195
        $this->schemaManager->dropAndCreateDatabase('test_create_database');
196
        $databases = $this->schemaManager->listDatabases();
197
198
        $databases = array_map('strtolower', $databases);
199
200
        self::assertContains('test_create_database', $databases);
201
    }
202
203
    /**
204
     * @group DBAL-1058
205
     */
206
    public function testListNamespaceNames() : void
207
    {
208
        if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) {
209
            self::markTestSkipped('Platform does not support schemas.');
210
        }
211
212
        // Currently dropping schemas is not supported, so we have to workaround here.
213
        $namespaces = $this->schemaManager->listNamespaceNames();
214
        $namespaces = array_map('strtolower', $namespaces);
215
216
        if (! in_array('test_create_schema', $namespaces, true)) {
217
            $this->connection->executeUpdate($this->schemaManager->getDatabasePlatform()->getCreateSchemaSQL('test_create_schema'));
218
219
            $namespaces = $this->schemaManager->listNamespaceNames();
220
            $namespaces = array_map('strtolower', $namespaces);
221
        }
222
223
        self::assertContains('test_create_schema', $namespaces);
224
    }
225
226
    public function testListTables() : void
227
    {
228
        $this->createTestTable('list_tables_test');
229
        $tables = $this->schemaManager->listTables();
230
231
        self::assertNotEmpty($tables, "List Tables has to find at least one table named 'list_tables_test'.");
232
233
        $foundTable = false;
234
        foreach ($tables as $table) {
235
            if (strtolower($table->getName()) !== 'list_tables_test') {
236
                continue;
237
            }
238
239
            $foundTable = true;
240
241
            self::assertTrue($table->hasColumn('id'));
242
            self::assertTrue($table->hasColumn('test'));
243
            self::assertTrue($table->hasColumn('foreign_key_test'));
244
        }
245
246
        self::assertTrue($foundTable, "The 'list_tables_test' table has to be found.");
247
    }
248
249
    public function createListTableColumns() : Table
250
    {
251
        $table = new Table('list_table_columns');
252
        $table->addColumn('id', 'integer', ['notnull' => true]);
253
        $table->addColumn('test', 'string', ['length' => 255, 'notnull' => false, 'default' => 'expected default']);
254
        $table->addColumn('foo', 'text', ['notnull' => true]);
255
        $table->addColumn('bar', 'decimal', ['precision' => 10, 'scale' => 4, 'notnull' => false]);
256
        $table->addColumn('baz1', 'datetime');
257
        $table->addColumn('baz2', 'time');
258
        $table->addColumn('baz3', 'date');
259
        $table->setPrimaryKey(['id']);
260
261
        return $table;
262
    }
263
264
    public function testListTableColumns() : void
265
    {
266
        $table = $this->createListTableColumns();
267
268
        $this->schemaManager->dropAndCreateTable($table);
269
270
        $columns     = $this->schemaManager->listTableColumns('list_table_columns');
271
        $columnsKeys = array_keys($columns);
272
273
        self::assertArrayHasKey('id', $columns);
274
        self::assertEquals(0, array_search('id', $columnsKeys, true));
275
        self::assertEquals('id', strtolower($columns['id']->getName()));
276
        self::assertInstanceOf(IntegerType::class, $columns['id']->getType());
277
        self::assertEquals(false, $columns['id']->getUnsigned());
278
        self::assertEquals(true, $columns['id']->getNotnull());
279
        self::assertEquals(null, $columns['id']->getDefault());
280
281
        self::assertArrayHasKey('test', $columns);
282
        self::assertEquals(1, array_search('test', $columnsKeys, true));
283
        self::assertEquals('test', strtolower($columns['test']->getName()));
284
        self::assertInstanceOf(StringType::class, $columns['test']->getType());
285
        self::assertEquals(255, $columns['test']->getLength());
286
        self::assertEquals(false, $columns['test']->getFixed());
287
        self::assertEquals(false, $columns['test']->getNotnull());
288
        self::assertEquals('expected default', $columns['test']->getDefault());
289
290
        self::assertEquals('foo', strtolower($columns['foo']->getName()));
291
        self::assertEquals(2, array_search('foo', $columnsKeys, true));
292
        self::assertInstanceOf(TextType::class, $columns['foo']->getType());
293
        self::assertEquals(false, $columns['foo']->getUnsigned());
294
        self::assertEquals(false, $columns['foo']->getFixed());
295
        self::assertEquals(true, $columns['foo']->getNotnull());
296
        self::assertEquals(null, $columns['foo']->getDefault());
297
298
        self::assertEquals('bar', strtolower($columns['bar']->getName()));
299
        self::assertEquals(3, array_search('bar', $columnsKeys, true));
300
        self::assertInstanceOf(DecimalType::class, $columns['bar']->getType());
301
        self::assertEquals(null, $columns['bar']->getLength());
302
        self::assertEquals(10, $columns['bar']->getPrecision());
303
        self::assertEquals(4, $columns['bar']->getScale());
304
        self::assertEquals(false, $columns['bar']->getUnsigned());
305
        self::assertEquals(false, $columns['bar']->getFixed());
306
        self::assertEquals(false, $columns['bar']->getNotnull());
307
        self::assertEquals(null, $columns['bar']->getDefault());
308
309
        self::assertEquals('baz1', strtolower($columns['baz1']->getName()));
310
        self::assertEquals(4, array_search('baz1', $columnsKeys, true));
311
        self::assertInstanceOf(DateTimeType::class, $columns['baz1']->getType());
312
        self::assertEquals(true, $columns['baz1']->getNotnull());
313
        self::assertEquals(null, $columns['baz1']->getDefault());
314
315
        self::assertEquals('baz2', strtolower($columns['baz2']->getName()));
316
        self::assertEquals(5, array_search('baz2', $columnsKeys, true));
317
        self::assertContains($columns['baz2']->getType()->getName(), ['time', 'date', 'datetime']);
318
        self::assertEquals(true, $columns['baz2']->getNotnull());
319
        self::assertEquals(null, $columns['baz2']->getDefault());
320
321
        self::assertEquals('baz3', strtolower($columns['baz3']->getName()));
322
        self::assertEquals(6, array_search('baz3', $columnsKeys, true));
323
        self::assertContains($columns['baz3']->getType()->getName(), ['time', 'date', 'datetime']);
324
        self::assertEquals(true, $columns['baz3']->getNotnull());
325
        self::assertEquals(null, $columns['baz3']->getDefault());
326
    }
327
328
    /**
329
     * @group DBAL-1078
330
     */
331
    public function testListTableColumnsWithFixedStringColumn() : void
332
    {
333
        $tableName = 'test_list_table_fixed_string';
334
335
        $table = new Table($tableName);
336
        $table->addColumn('column_char', 'string', ['fixed' => true, 'length' => 2]);
337
338
        $this->schemaManager->createTable($table);
339
340
        $columns = $this->schemaManager->listTableColumns($tableName);
341
342
        self::assertArrayHasKey('column_char', $columns);
343
        self::assertInstanceOf(StringType::class, $columns['column_char']->getType());
344
        self::assertTrue($columns['column_char']->getFixed());
345
        self::assertSame(2, $columns['column_char']->getLength());
346
    }
347
348
    public function testListTableColumnsDispatchEvent() : void
349
    {
350
        $table = $this->createListTableColumns();
351
352
        $this->schemaManager->dropAndCreateTable($table);
353
354
        $listenerMock = $this->getMockBuilder($this->getMockClass('ListTableColumnsDispatchEventListener'))
355
            ->addMethods(['onSchemaColumnDefinition'])
356
            ->getMock();
357
358
        $listenerMock
359
            ->expects(self::exactly(7))
360
            ->method('onSchemaColumnDefinition');
361
362
        $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager();
363
        assert($oldEventManager instanceof EventManager);
364
365
        $eventManager = new EventManager();
366
        $eventManager->addEventListener([Events::onSchemaColumnDefinition], $listenerMock);
367
368
        $this->schemaManager->getDatabasePlatform()->setEventManager($eventManager);
369
370
        $this->schemaManager->listTableColumns('list_table_columns');
371
372
        $this->schemaManager->getDatabasePlatform()->setEventManager($oldEventManager);
373
    }
374
375
    public function testListTableIndexesDispatchEvent() : void
376
    {
377
        $table = $this->getTestTable('list_table_indexes_test');
378
        $table->addUniqueIndex(['test'], 'test_index_name');
379
        $table->addIndex(['id', 'test'], 'test_composite_idx');
380
381
        $this->schemaManager->dropAndCreateTable($table);
382
383
        $listenerMock = $this->getMockBuilder($this->getMockClass('ListTableIndexesDispatchEventListener'))
384
            ->addMethods(['onSchemaIndexDefinition'])
385
            ->getMock();
386
        $listenerMock
387
            ->expects(self::exactly(3))
388
            ->method('onSchemaIndexDefinition');
389
390
        $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager();
391
        assert($oldEventManager instanceof EventManager);
392
393
        $eventManager = new EventManager();
394
        $eventManager->addEventListener([Events::onSchemaIndexDefinition], $listenerMock);
395
396
        $this->schemaManager->getDatabasePlatform()->setEventManager($eventManager);
397
398
        $this->schemaManager->listTableIndexes('list_table_indexes_test');
399
400
        $this->schemaManager->getDatabasePlatform()->setEventManager($oldEventManager);
401
    }
402
403
    public function testDiffListTableColumns() : void
404
    {
405
        if ($this->schemaManager->getDatabasePlatform()->getName() === 'oracle') {
406
            self::markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).');
407
        }
408
409
        $offlineTable = $this->createListTableColumns();
410
        $this->schemaManager->dropAndCreateTable($offlineTable);
411
        $onlineTable = $this->schemaManager->listTableDetails('list_table_columns');
412
413
        $comparator = new Comparator();
414
        $diff       = $comparator->diffTable($offlineTable, $onlineTable);
415
416
        self::assertNull($diff, 'No differences should be detected with the offline vs online schema.');
417
    }
418
419
    public function testListTableIndexes() : void
420
    {
421
        $table = $this->getTestCompositeTable('list_table_indexes_test');
422
        $table->addUniqueIndex(['test'], 'test_index_name');
423
        $table->addIndex(['id', 'test'], 'test_composite_idx');
424
425
        $this->schemaManager->dropAndCreateTable($table);
426
427
        $tableIndexes = $this->schemaManager->listTableIndexes('list_table_indexes_test');
428
429
        self::assertEquals(3, count($tableIndexes));
430
431
        self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
432
        self::assertEquals(['id', 'other_id'], array_map('strtolower', $tableIndexes['primary']->getColumns()));
433
        self::assertTrue($tableIndexes['primary']->isUnique());
434
        self::assertTrue($tableIndexes['primary']->isPrimary());
435
436
        self::assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName()));
437
        self::assertEquals(['test'], array_map('strtolower', $tableIndexes['test_index_name']->getColumns()));
438
        self::assertTrue($tableIndexes['test_index_name']->isUnique());
439
        self::assertFalse($tableIndexes['test_index_name']->isPrimary());
440
441
        self::assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName()));
442
        self::assertEquals(['id', 'test'], array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns()));
443
        self::assertFalse($tableIndexes['test_composite_idx']->isUnique());
444
        self::assertFalse($tableIndexes['test_composite_idx']->isPrimary());
445
    }
446
447
    public function testDropAndCreateIndex() : void
448
    {
449
        $table = $this->getTestTable('test_create_index');
450
        $table->addUniqueIndex(['test'], 'test');
451
        $this->schemaManager->dropAndCreateTable($table);
452
453
        $this->schemaManager->dropAndCreateIndex($table->getIndex('test'), $table);
454
        $tableIndexes = $this->schemaManager->listTableIndexes('test_create_index');
455
456
        self::assertEquals('test', strtolower($tableIndexes['test']->getName()));
457
        self::assertEquals(['test'], array_map('strtolower', $tableIndexes['test']->getColumns()));
458
        self::assertTrue($tableIndexes['test']->isUnique());
459
        self::assertFalse($tableIndexes['test']->isPrimary());
460
    }
461
462
    public function testCreateTableWithForeignKeys() : void
463
    {
464
        if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) {
465
            self::markTestSkipped('Platform does not support foreign keys.');
466
        }
467
468
        $tableB = $this->getTestTable('test_foreign');
469
470
        $this->schemaManager->dropAndCreateTable($tableB);
471
472
        $tableA = $this->getTestTable('test_create_fk');
473
        $tableA->addForeignKeyConstraint('test_foreign', ['foreign_key_test'], ['id']);
474
475
        $this->schemaManager->dropAndCreateTable($tableA);
476
477
        $fkTable       = $this->schemaManager->listTableDetails('test_create_fk');
478
        $fkConstraints = $fkTable->getForeignKeys();
479
        self::assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key.");
480
481
        $fkConstraint = current($fkConstraints);
482
        self::assertInstanceOf(ForeignKeyConstraint::class, $fkConstraint);
483
        self::assertEquals('test_foreign', strtolower($fkConstraint->getForeignTableName()));
484
        self::assertEquals(['foreign_key_test'], array_map('strtolower', $fkConstraint->getColumns()));
485
        self::assertEquals(['id'], array_map('strtolower', $fkConstraint->getForeignColumns()));
486
487
        self::assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), 'The columns of a foreign key constraint should always be indexed.');
488
    }
489
490
    public function testListForeignKeys() : void
491
    {
492
        if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) {
493
            self::markTestSkipped('Does not support foreign key constraints.');
494
        }
495
496
        $this->createTestTable('test_create_fk1');
497
        $this->createTestTable('test_create_fk2');
498
499
        $foreignKey = new ForeignKeyConstraint(
500
            ['foreign_key_test'],
501
            'test_create_fk2',
502
            ['id'],
503
            'foreign_key_test_fk',
504
            ['onDelete' => 'CASCADE']
505
        );
506
507
        $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1');
508
509
        $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1');
510
511
        self::assertCount(1, $fkeys, "Table 'test_create_fk1' has to have one foreign key.");
512
513
        self::assertEquals(['foreign_key_test'], array_map('strtolower', $fkeys[0]->getLocalColumns()));
514
        self::assertEquals(['id'], array_map('strtolower', $fkeys[0]->getForeignColumns()));
515
        self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
516
517
        if (! $fkeys[0]->hasOption('onDelete')) {
518
            return;
519
        }
520
521
        self::assertEquals('CASCADE', $fkeys[0]->getOption('onDelete'));
522
    }
523
524
    protected function getCreateExampleViewSql() : void
525
    {
526
        self::markTestSkipped('No Create Example View SQL was defined for this SchemaManager');
527
    }
528
529
    public function testCreateSchema() : void
530
    {
531
        $this->createTestTable('test_table');
532
533
        $schema = $this->schemaManager->createSchema();
534
        self::assertTrue($schema->hasTable('test_table'));
535
    }
536
537
    public function testAlterTableScenario() : void
538
    {
539
        if (! $this->schemaManager->getDatabasePlatform()->supportsAlterTable()) {
540
            self::markTestSkipped('Alter Table is not supported by this platform.');
541
        }
542
543
        $alterTable = $this->createTestTable('alter_table');
544
        $this->createTestTable('alter_table_foreign');
545
546
        $table = $this->schemaManager->listTableDetails('alter_table');
547
        self::assertTrue($table->hasColumn('id'));
548
        self::assertTrue($table->hasColumn('test'));
549
        self::assertTrue($table->hasColumn('foreign_key_test'));
550
        self::assertEquals(0, count($table->getForeignKeys()));
551
        self::assertEquals(1, count($table->getIndexes()));
552
553
        $tableDiff                         = new TableDiff('alter_table');
554
        $tableDiff->fromTable              = $alterTable;
555
        $tableDiff->addedColumns['foo']    = new Column('foo', Type::getType('integer'));
556
        $tableDiff->removedColumns['test'] = $table->getColumn('test');
557
558
        $this->schemaManager->alterTable($tableDiff);
559
560
        $table = $this->schemaManager->listTableDetails('alter_table');
561
        self::assertFalse($table->hasColumn('test'));
562
        self::assertTrue($table->hasColumn('foo'));
563
564
        $tableDiff                          = new TableDiff('alter_table');
565
        $tableDiff->fromTable               = $table;
566
        $tableDiff->addedIndexes['foo_idx'] = new Index('foo_idx', ['foo']);
567
568
        $this->schemaManager->alterTable($tableDiff);
569
570
        $table = $this->schemaManager->listTableDetails('alter_table');
571
        self::assertEquals(2, count($table->getIndexes()));
572
        self::assertTrue($table->hasIndex('foo_idx'));
573
        self::assertEquals(['foo'], array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
574
        self::assertFalse($table->getIndex('foo_idx')->isPrimary());
575
        self::assertFalse($table->getIndex('foo_idx')->isUnique());
576
577
        $tableDiff                            = new TableDiff('alter_table');
578
        $tableDiff->fromTable                 = $table;
579
        $tableDiff->changedIndexes['foo_idx'] = new Index('foo_idx', ['foo', 'foreign_key_test']);
580
581
        $this->schemaManager->alterTable($tableDiff);
582
583
        $table = $this->schemaManager->listTableDetails('alter_table');
584
        self::assertEquals(2, count($table->getIndexes()));
585
        self::assertTrue($table->hasIndex('foo_idx'));
586
        self::assertEquals(['foo', 'foreign_key_test'], array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
587
588
        $tableDiff                            = new TableDiff('alter_table');
589
        $tableDiff->fromTable                 = $table;
590
        $tableDiff->renamedIndexes['foo_idx'] = new Index('bar_idx', ['foo', 'foreign_key_test']);
591
592
        $this->schemaManager->alterTable($tableDiff);
593
594
        $table = $this->schemaManager->listTableDetails('alter_table');
595
        self::assertEquals(2, count($table->getIndexes()));
596
        self::assertTrue($table->hasIndex('bar_idx'));
597
        self::assertFalse($table->hasIndex('foo_idx'));
598
        self::assertEquals(['foo', 'foreign_key_test'], array_map('strtolower', $table->getIndex('bar_idx')->getColumns()));
599
        self::assertFalse($table->getIndex('bar_idx')->isPrimary());
600
        self::assertFalse($table->getIndex('bar_idx')->isUnique());
601
602
        $tableDiff                            = new TableDiff('alter_table');
603
        $tableDiff->fromTable                 = $table;
604
        $tableDiff->removedIndexes['bar_idx'] = new Index('bar_idx', ['foo', 'foreign_key_test']);
605
        $fk                                   = new ForeignKeyConstraint(['foreign_key_test'], 'alter_table_foreign', ['id']);
606
        $tableDiff->addedForeignKeys[]        = $fk;
607
608
        $this->schemaManager->alterTable($tableDiff);
609
        $table = $this->schemaManager->listTableDetails('alter_table');
610
611
        // dont check for index size here, some platforms automatically add indexes for foreign keys.
612
        self::assertFalse($table->hasIndex('bar_idx'));
613
614
        if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) {
615
            return;
616
        }
617
618
        $fks = $table->getForeignKeys();
619
        self::assertCount(1, $fks);
620
        $foreignKey = current($fks);
621
        self::assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName()));
622
        self::assertEquals(['foreign_key_test'], array_map('strtolower', $foreignKey->getColumns()));
623
        self::assertEquals(['id'], array_map('strtolower', $foreignKey->getForeignColumns()));
624
    }
625
626
    public function testTableInNamespace() : void
627
    {
628
        if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) {
629
            self::markTestSkipped('Schema definition is not supported by this platform.');
630
        }
631
632
        //create schema
633
        $diff                              = new SchemaDiff();
634
        $diff->newNamespaces['testschema'] = 'testschema';
635
636
        foreach ($diff->toSql($this->schemaManager->getDatabasePlatform()) as $sql) {
637
            $this->connection->exec($sql);
638
        }
639
640
        //test if table is create in namespace
641
        $this->createTestTable('testschema.my_table_in_namespace');
642
        self::assertContains('testschema.my_table_in_namespace', $this->schemaManager->listTableNames());
643
644
        //tables without namespace should be created in default namespace
645
        //default namespaces are ignored in table listings
646
        $this->createTestTable('my_table_not_in_namespace');
647
        self::assertContains('my_table_not_in_namespace', $this->schemaManager->listTableNames());
648
    }
649
650
    public function testCreateAndListViews() : void
651
    {
652
        if (! $this->schemaManager->getDatabasePlatform()->supportsViews()) {
653
            self::markTestSkipped('Views is not supported by this platform.');
654
        }
655
656
        $this->createTestTable('view_test_table');
657
658
        $name = 'doctrine_test_view';
659
        $sql  = 'SELECT * FROM view_test_table';
660
661
        $view = new View($name, $sql);
662
663
        $this->schemaManager->dropAndCreateView($view);
664
665
        self::assertTrue($this->hasElementWithName($this->schemaManager->listViews(), $name));
666
    }
667
668
    public function testAutoincrementDetection() : void
669
    {
670
        if (! $this->schemaManager->getDatabasePlatform()->supportsIdentityColumns()) {
671
            self::markTestSkipped('This test is only supported on platforms that have autoincrement');
672
        }
673
674
        $table = new Table('test_autoincrement');
675
        $table->setSchemaConfig($this->schemaManager->createSchemaConfig());
676
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
677
        $table->setPrimaryKey(['id']);
678
679
        $this->schemaManager->createTable($table);
680
681
        $inferredTable = $this->schemaManager->listTableDetails('test_autoincrement');
682
        self::assertTrue($inferredTable->hasColumn('id'));
683
        self::assertTrue($inferredTable->getColumn('id')->getAutoincrement());
684
    }
685
686
    /**
687
     * @group DBAL-792
688
     */
689
    public function testAutoincrementDetectionMulticolumns() : void
690
    {
691
        if (! $this->schemaManager->getDatabasePlatform()->supportsIdentityColumns()) {
692
            self::markTestSkipped('This test is only supported on platforms that have autoincrement');
693
        }
694
695
        $table = new Table('test_not_autoincrement');
696
        $table->setSchemaConfig($this->schemaManager->createSchemaConfig());
697
        $table->addColumn('id', 'integer');
698
        $table->addColumn('other_id', 'integer');
699
        $table->setPrimaryKey(['id', 'other_id']);
700
701
        $this->schemaManager->createTable($table);
702
703
        $inferredTable = $this->schemaManager->listTableDetails('test_not_autoincrement');
704
        self::assertTrue($inferredTable->hasColumn('id'));
705
        self::assertFalse($inferredTable->getColumn('id')->getAutoincrement());
706
    }
707
708
    /**
709
     * @group DDC-887
710
     */
711
    public function testUpdateSchemaWithForeignKeyRenaming() : void
712
    {
713
        if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) {
714
            self::markTestSkipped('This test is only supported on platforms that have foreign keys.');
715
        }
716
717
        $table = new Table('test_fk_base');
718
        $table->addColumn('id', 'integer');
719
        $table->setPrimaryKey(['id']);
720
721
        $tableFK = new Table('test_fk_rename');
722
        $tableFK->setSchemaConfig($this->schemaManager->createSchemaConfig());
723
        $tableFK->addColumn('id', 'integer');
724
        $tableFK->addColumn('fk_id', 'integer');
725
        $tableFK->setPrimaryKey(['id']);
726
        $tableFK->addIndex(['fk_id'], 'fk_idx');
727
        $tableFK->addForeignKeyConstraint('test_fk_base', ['fk_id'], ['id']);
728
729
        $this->schemaManager->createTable($table);
730
        $this->schemaManager->createTable($tableFK);
731
732
        $tableFKNew = new Table('test_fk_rename');
733
        $tableFKNew->setSchemaConfig($this->schemaManager->createSchemaConfig());
734
        $tableFKNew->addColumn('id', 'integer');
735
        $tableFKNew->addColumn('rename_fk_id', 'integer');
736
        $tableFKNew->setPrimaryKey(['id']);
737
        $tableFKNew->addIndex(['rename_fk_id'], 'fk_idx');
738
        $tableFKNew->addForeignKeyConstraint('test_fk_base', ['rename_fk_id'], ['id']);
739
740
        $c         = new Comparator();
741
        $tableDiff = $c->diffTable($tableFK, $tableFKNew);
742
743
        self::assertNotNull($tableDiff);
744
745
        $this->schemaManager->alterTable($tableDiff);
746
747
        $table       = $this->schemaManager->listTableDetails('test_fk_rename');
748
        $foreignKeys = $table->getForeignKeys();
749
750
        self::assertTrue($table->hasColumn('rename_fk_id'));
751
        self::assertCount(1, $foreignKeys);
752
        self::assertSame(['rename_fk_id'], array_map('strtolower', current($foreignKeys)->getColumns()));
753
    }
754
755
    /**
756
     * @group DBAL-1062
757
     */
758
    public function testRenameIndexUsedInForeignKeyConstraint() : void
759
    {
760
        if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) {
761
            self::markTestSkipped('This test is only supported on platforms that have foreign keys.');
762
        }
763
764
        $primaryTable = new Table('test_rename_index_primary');
765
        $primaryTable->addColumn('id', 'integer');
766
        $primaryTable->setPrimaryKey(['id']);
767
768
        $foreignTable = new Table('test_rename_index_foreign');
769
        $foreignTable->addColumn('fk', 'integer');
770
        $foreignTable->addIndex(['fk'], 'rename_index_fk_idx');
771
        $foreignTable->addForeignKeyConstraint(
772
            'test_rename_index_primary',
773
            ['fk'],
774
            ['id'],
775
            [],
776
            'fk_constraint'
777
        );
778
779
        $this->schemaManager->dropAndCreateTable($primaryTable);
780
        $this->schemaManager->dropAndCreateTable($foreignTable);
781
782
        $foreignTable2 = clone $foreignTable;
783
        $foreignTable2->renameIndex('rename_index_fk_idx', 'renamed_index_fk_idx');
784
785
        $comparator = new Comparator();
786
787
        $diff = $comparator->diffTable($foreignTable, $foreignTable2);
788
789
        self::assertNotNull($diff);
790
791
        $this->schemaManager->alterTable($diff);
792
793
        $foreignTable = $this->schemaManager->listTableDetails('test_rename_index_foreign');
794
795
        self::assertFalse($foreignTable->hasIndex('rename_index_fk_idx'));
796
        self::assertTrue($foreignTable->hasIndex('renamed_index_fk_idx'));
797
        self::assertTrue($foreignTable->hasForeignKey('fk_constraint'));
798
    }
799
800
    /**
801
     * @group DBAL-825
802
     */
803
    public function testChangeColumnsTypeWithDefaultValue() : void
804
    {
805
        $tableName = 'column_def_change_type';
806
        $table     = new Table($tableName);
807
808
        $table->addColumn('col_int', 'smallint', ['default' => 666]);
809
        $table->addColumn('col_string', 'string', [
810
            'length' => 3,
811
            'default' => 'foo',
812
        ]);
813
814
        $this->schemaManager->dropAndCreateTable($table);
815
816
        $tableDiff                            = new TableDiff($tableName);
817
        $tableDiff->fromTable                 = $table;
818
        $tableDiff->changedColumns['col_int'] = new ColumnDiff(
819
            'col_int',
820
            new Column('col_int', Type::getType('integer'), ['default' => 666]),
821
            ['type'],
822
            new Column('col_int', Type::getType('smallint'), ['default' => 666])
823
        );
824
825
        $tableDiff->changedColumns['col_string'] = new ColumnDiff(
826
            'col_string',
827
            new Column('col_string', Type::getType('string'), [
828
                'length' => 3,
829
                'fixed' => true,
830
                'default' => 'foo',
831
            ]),
832
            ['fixed'],
833
            new Column('col_string', Type::getType('string'), [
834
                'length' => 3,
835
                'default' => 'foo',
836
            ])
837
        );
838
839
        $this->schemaManager->alterTable($tableDiff);
840
841
        $columns = $this->schemaManager->listTableColumns($tableName);
842
843
        self::assertInstanceOf(IntegerType::class, $columns['col_int']->getType());
844
        self::assertEquals(666, $columns['col_int']->getDefault());
845
846
        self::assertInstanceOf(StringType::class, $columns['col_string']->getType());
847
        self::assertEquals('foo', $columns['col_string']->getDefault());
848
    }
849
850
    /**
851
     * @group DBAL-197
852
     */
853
    public function testListTableWithBlob() : void
854
    {
855
        $table = new Table('test_blob_table');
856
        $table->addColumn('id', 'integer');
857
        $table->addColumn('binarydata', 'blob', []);
858
        $table->setPrimaryKey(['id']);
859
860
        $this->schemaManager->createTable($table);
861
862
        $created = $this->schemaManager->listTableDetails('test_blob_table');
863
864
        self::assertTrue($created->hasColumn('id'));
865
        self::assertTrue($created->hasColumn('binarydata'));
866
        self::assertTrue($created->hasPrimaryKey());
867
    }
868
869
    /**
870
     * @param mixed[] $data
871
     */
872
    protected function createTestTable(string $name = 'test_table', array $data = []) : Table
873
    {
874
        $options = $data['options'] ?? [];
875
876
        $table = $this->getTestTable($name, $options);
877
878
        $this->schemaManager->dropAndCreateTable($table);
879
880
        return $table;
881
    }
882
883
    /**
884
     * @param mixed[] $options
885
     */
886
    protected function getTestTable(string $name, array $options = []) : Table
887
    {
888
        $table = new Table($name, [], [], [], [], $options);
889
        $table->setSchemaConfig($this->schemaManager->createSchemaConfig());
890
        $table->addColumn('id', 'integer', ['notnull' => true]);
891
        $table->setPrimaryKey(['id']);
892
        $table->addColumn('test', 'string', ['length' => 255]);
893
        $table->addColumn('foreign_key_test', 'integer');
894
895
        return $table;
896
    }
897
898
    protected function getTestCompositeTable(string $name) : Table
899
    {
900
        $table = new Table($name, [], [], [], [], []);
901
        $table->setSchemaConfig($this->schemaManager->createSchemaConfig());
902
        $table->addColumn('id', 'integer', ['notnull' => true]);
903
        $table->addColumn('other_id', 'integer', ['notnull' => true]);
904
        $table->setPrimaryKey(['id', 'other_id']);
905
        $table->addColumn('test', 'string', ['length' => 255]);
906
907
        return $table;
908
    }
909
910
    /**
911
     * @param Table[] $tables
912
     */
913
    protected function assertHasTable(array $tables) : void
914
    {
915
        $foundTable = false;
916
917
        foreach ($tables as $table) {
918
            if (strtolower($table->getName()) !== 'list_tables_test_new_name') {
919
                continue;
920
            }
921
922
            $foundTable = true;
923
        }
924
925
        self::assertTrue($foundTable, 'Could not find new table');
926
    }
927
928
    public function testListForeignKeysComposite() : void
929
    {
930
        if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) {
931
            self::markTestSkipped('Does not support foreign key constraints.');
932
        }
933
934
        $this->schemaManager->createTable($this->getTestTable('test_create_fk3'));
935
        $this->schemaManager->createTable($this->getTestCompositeTable('test_create_fk4'));
936
937
        $foreignKey = new ForeignKeyConstraint(
938
            ['id', 'foreign_key_test'],
939
            'test_create_fk4',
940
            ['id', 'other_id'],
941
            'foreign_key_test_fk2'
942
        );
943
944
        $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk3');
945
946
        $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk3');
947
948
        self::assertCount(1, $fkeys, "Table 'test_create_fk3' has to have one foreign key.");
949
950
        self::assertEquals(['id', 'foreign_key_test'], array_map('strtolower', $fkeys[0]->getLocalColumns()));
951
        self::assertEquals(['id', 'other_id'], array_map('strtolower', $fkeys[0]->getForeignColumns()));
952
    }
953
954
    /**
955
     * @group DBAL-44
956
     */
957
    public function testColumnDefaultLifecycle() : void
958
    {
959
        $table = new Table('col_def_lifecycle');
960
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
961
        $table->addColumn('column1', 'string', [
962
            'length' => 1,
963
            'default' => null,
964
        ]);
965
        $table->addColumn('column2', 'string', [
966
            'length' => 1,
967
            'default' => '',
968
        ]);
969
        $table->addColumn('column3', 'string', [
970
            'length' => 8,
971
            'default' => 'default1',
972
        ]);
973
        $table->addColumn('column4', 'integer', [
974
            'length' => 1,
975
            'default' => 0,
976
        ]);
977
        $table->setPrimaryKey(['id']);
978
979
        $this->schemaManager->dropAndCreateTable($table);
980
981
        $columns = $this->schemaManager->listTableColumns('col_def_lifecycle');
982
983
        self::assertNull($columns['id']->getDefault());
984
        self::assertNull($columns['column1']->getDefault());
985
        self::assertSame('', $columns['column2']->getDefault());
986
        self::assertSame('default1', $columns['column3']->getDefault());
987
        self::assertSame('0', $columns['column4']->getDefault());
988
989
        $diffTable = clone $table;
990
991
        $diffTable->changeColumn('column1', ['default' => '']);
992
        $diffTable->changeColumn('column2', ['default' => null]);
993
        $diffTable->changeColumn('column3', ['default' => 'default2']);
994
        $diffTable->changeColumn('column4', ['default' => null]);
995
996
        $comparator = new Comparator();
997
998
        $diff = $comparator->diffTable($table, $diffTable);
999
1000
        self::assertNotNull($diff);
1001
1002
        $this->schemaManager->alterTable($diff);
1003
1004
        $columns = $this->schemaManager->listTableColumns('col_def_lifecycle');
1005
1006
        self::assertSame('', $columns['column1']->getDefault());
1007
        self::assertNull($columns['column2']->getDefault());
1008
        self::assertSame('default2', $columns['column3']->getDefault());
1009
        self::assertNull($columns['column4']->getDefault());
1010
    }
1011
1012
    public function testListTableWithBinary() : void
1013
    {
1014
        $tableName = 'test_binary_table';
1015
1016
        $table = new Table($tableName);
1017
        $table->addColumn('id', 'integer');
1018
        $table->addColumn('column_varbinary', 'binary', ['length' => 16]);
1019
        $table->addColumn('column_binary', 'binary', ['fixed' => true]);
1020
        $table->setPrimaryKey(['id']);
1021
1022
        $this->schemaManager->createTable($table);
1023
1024
        $table = $this->schemaManager->listTableDetails($tableName);
1025
1026
        self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType());
1027
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
1028
1029
        self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType());
1030
        self::assertTrue($table->getColumn('column_binary')->getFixed());
1031
    }
1032
1033
    public function testListTableDetailsWithFullQualifiedTableName() : void
1034
    {
1035
        if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) {
1036
            self::markTestSkipped('Test only works on platforms that support schemas.');
1037
        }
1038
1039
        $defaultSchemaName = $this->schemaManager->getDatabasePlatform()->getDefaultSchemaName();
1040
        $primaryTableName  = 'primary_table';
1041
        $foreignTableName  = 'foreign_table';
1042
1043
        $table = new Table($foreignTableName);
1044
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
1045
        $table->setPrimaryKey(['id']);
1046
1047
        $this->schemaManager->dropAndCreateTable($table);
1048
1049
        $table = new Table($primaryTableName);
1050
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
1051
        $table->addColumn('foo', 'integer');
1052
        $table->addColumn('bar', 'string', ['length' => 32]);
1053
        $table->addForeignKeyConstraint($foreignTableName, ['foo'], ['id']);
1054
        $table->addIndex(['bar']);
1055
        $table->setPrimaryKey(['id']);
1056
1057
        $this->schemaManager->dropAndCreateTable($table);
1058
1059
        self::assertEquals(
1060
            $this->schemaManager->listTableColumns($primaryTableName),
1061
            $this->schemaManager->listTableColumns($defaultSchemaName . '.' . $primaryTableName)
1062
        );
1063
        self::assertEquals(
1064
            $this->schemaManager->listTableIndexes($primaryTableName),
1065
            $this->schemaManager->listTableIndexes($defaultSchemaName . '.' . $primaryTableName)
1066
        );
1067
        self::assertEquals(
1068
            $this->schemaManager->listTableForeignKeys($primaryTableName),
1069
            $this->schemaManager->listTableForeignKeys($defaultSchemaName . '.' . $primaryTableName)
1070
        );
1071
    }
1072
1073
    /**
1074
     * @group DBAL-1095
1075
     */
1076
    public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys() : void
1077
    {
1078
        if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) {
1079
            self::markTestSkipped('This test is only supported on platforms that have foreign keys.');
1080
        }
1081
1082
        $primaryTable = new Table('test_list_index_impl_primary');
1083
        $primaryTable->addColumn('id', 'integer');
1084
        $primaryTable->setPrimaryKey(['id']);
1085
1086
        $foreignTable = new Table('test_list_index_impl_foreign');
1087
        $foreignTable->addColumn('fk1', 'integer');
1088
        $foreignTable->addColumn('fk2', 'integer');
1089
        $foreignTable->addIndex(['fk1'], 'explicit_fk1_idx');
1090
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', ['fk1'], ['id']);
1091
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', ['fk2'], ['id']);
1092
1093
        $this->schemaManager->dropAndCreateTable($primaryTable);
1094
        $this->schemaManager->dropAndCreateTable($foreignTable);
1095
1096
        $indexes = $this->schemaManager->listTableIndexes('test_list_index_impl_foreign');
1097
1098
        self::assertCount(2, $indexes);
1099
        self::assertArrayHasKey('explicit_fk1_idx', $indexes);
1100
        self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes);
1101
    }
1102
1103
    /**
1104
     * @group 2782
1105
     * @group 6654
1106
     */
1107
    public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNow() : void
1108
    {
1109
        if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) {
1110
            self::markTestSkipped('This test is only supported on platforms that have native JSON type.');
1111
        }
1112
1113
        $this->connection->executeQuery('CREATE TABLE json_test (parameters JSON NOT NULL)');
1114
1115
        $table = new Table('json_test');
1116
        $table->addColumn('parameters', 'json');
1117
1118
        $comparator = new Comparator();
1119
        $tableDiff  = $comparator->diffTable($this->schemaManager->listTableDetails('json_test'), $table);
1120
1121
        self::assertNull($tableDiff);
1122
    }
1123
1124
    /**
1125
     * @dataProvider commentsProvider
1126
     * @group 2596
1127
     */
1128
    public function testExtractDoctrineTypeFromComment(string $comment, ?string $expectedType) : void
1129
    {
1130
        $re = new ReflectionMethod($this->schemaManager, 'extractDoctrineTypeFromComment');
1131
        $re->setAccessible(true);
1132
1133
        self::assertSame($expectedType, $re->invokeArgs($this->schemaManager, [&$comment]));
1134
    }
1135
1136
    /**
1137
     * @return mixed[][]
1138
     */
1139
    public static function commentsProvider() : iterable
1140
    {
1141
        return [
1142
            'invalid custom type comments'      => ['should.return.null', null],
1143
            'valid doctrine type'               => ['(DC2Type:guid)', 'guid'],
1144
            'valid with dots'                   => ['(DC2Type:type.should.return)', 'type.should.return'],
1145
            'valid with namespace'              => ['(DC2Type:Namespace\Class)', 'Namespace\Class'],
1146
            'valid with extra closing bracket'  => ['(DC2Type:should.stop)).before)', 'should.stop'],
1147
            'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop'],
1148
        ];
1149
    }
1150
1151
    public function testCreateAndListSequences() : void
1152
    {
1153
        if (! $this->schemaManager->getDatabasePlatform()->supportsSequences()) {
1154
            self::markTestSkipped('This test is only supported on platforms that support sequences.');
1155
        }
1156
1157
        $sequence1Name           = 'sequence_1';
1158
        $sequence1AllocationSize = 1;
1159
        $sequence1InitialValue   = 2;
1160
        $sequence2Name           = 'sequence_2';
1161
        $sequence2AllocationSize = 3;
1162
        $sequence2InitialValue   = 4;
1163
        $sequence1               = new Sequence($sequence1Name, $sequence1AllocationSize, $sequence1InitialValue);
1164
        $sequence2               = new Sequence($sequence2Name, $sequence2AllocationSize, $sequence2InitialValue);
1165
1166
        $this->schemaManager->createSequence($sequence1);
1167
        $this->schemaManager->createSequence($sequence2);
1168
1169
        /** @var Sequence[] $actualSequences */
1170
        $actualSequences = [];
1171
        foreach ($this->schemaManager->listSequences() as $sequence) {
1172
            $actualSequences[$sequence->getName()] = $sequence;
1173
        }
1174
1175
        $actualSequence1 = $actualSequences[$sequence1Name];
1176
        $actualSequence2 = $actualSequences[$sequence2Name];
1177
1178
        self::assertSame($sequence1Name, $actualSequence1->getName());
1179
        self::assertEquals($sequence1AllocationSize, $actualSequence1->getAllocationSize());
1180
        self::assertEquals($sequence1InitialValue, $actualSequence1->getInitialValue());
1181
1182
        self::assertSame($sequence2Name, $actualSequence2->getName());
1183
        self::assertEquals($sequence2AllocationSize, $actualSequence2->getAllocationSize());
1184
        self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue());
1185
    }
1186
1187
    /**
1188
     * @group #3086
1189
     */
1190
    public function testComparisonWithAutoDetectedSequenceDefinition() : void
1191
    {
1192
        if (! $this->schemaManager->getDatabasePlatform()->supportsSequences()) {
1193
            self::markTestSkipped('This test is only supported on platforms that support sequences.');
1194
        }
1195
1196
        $sequenceName           = 'sequence_auto_detect_test';
1197
        $sequenceAllocationSize = 5;
1198
        $sequenceInitialValue   = 10;
1199
        $sequence               = new Sequence($sequenceName, $sequenceAllocationSize, $sequenceInitialValue);
1200
1201
        $this->schemaManager->dropAndCreateSequence($sequence);
1202
1203
        $createdSequence = array_values(
1204
            array_filter(
1205
                $this->schemaManager->listSequences(),
1206
                static function (Sequence $sequence) use ($sequenceName) : bool {
1207
                    return strcasecmp($sequence->getName(), $sequenceName) === 0;
1208
                }
1209
            )
1210
        )[0] ?? null;
1211
1212
        self::assertNotNull($createdSequence);
1213
1214
        $comparator = new Comparator();
1215
        $tableDiff  = $comparator->diffSequence($createdSequence, $sequence);
1216
1217
        self::assertFalse($tableDiff);
1218
    }
1219
1220
    /**
1221
     * @group DBAL-2921
1222
     */
1223
    public function testPrimaryKeyAutoIncrement() : void
1224
    {
1225
        $table = new Table('test_pk_auto_increment');
1226
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
1227
        $table->addColumn('text', 'string', ['length' => 1]);
1228
        $table->setPrimaryKey(['id']);
1229
        $this->schemaManager->dropAndCreateTable($table);
1230
1231
        $this->connection->insert('test_pk_auto_increment', ['text' => '1']);
1232
1233
        $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'1\'');
1234
        assert($query instanceof Statement);
1235
1236
        $query->execute();
1237
        $lastUsedIdBeforeDelete = (int) $query->fetchColumn();
1238
1239
        $this->connection->query('DELETE FROM test_pk_auto_increment');
1240
1241
        $this->connection->insert('test_pk_auto_increment', ['text' => '2']);
1242
1243
        $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'2\'');
1244
        assert($query instanceof Statement);
1245
1246
        $query->execute();
1247
        $lastUsedIdAfterDelete = (int) $query->fetchColumn();
1248
1249
        self::assertGreaterThan($lastUsedIdBeforeDelete, $lastUsedIdAfterDelete);
1250
    }
1251
1252
    public function testGenerateAnIndexWithPartialColumnLength() : void
1253
    {
1254
        if (! $this->schemaManager->getDatabasePlatform()->supportsColumnLengthIndexes()) {
1255
            self::markTestSkipped('This test is only supported on platforms that support indexes with column length definitions.');
1256
        }
1257
1258
        $table = new Table('test_partial_column_index');
1259
        $table->addColumn('long_column', 'string', ['length' => 40]);
1260
        $table->addColumn('standard_column', 'integer');
1261
        $table->addIndex(['long_column'], 'partial_long_column_idx', [], ['lengths' => [4]]);
1262
        $table->addIndex(['standard_column', 'long_column'], 'standard_and_partial_idx', [], ['lengths' => [null, 2]]);
1263
1264
        $expected = $table->getIndexes();
1265
1266
        $this->schemaManager->dropAndCreateTable($table);
1267
1268
        $onlineTable = $this->schemaManager->listTableDetails('test_partial_column_index');
1269
        self::assertEquals($expected, $onlineTable->getIndexes());
1270
    }
1271
1272
    public function testCommentInTable() : void
1273
    {
1274
        $table = new Table('table_with_comment');
1275
        $table->addColumn('id', 'integer');
1276
        $table->setComment('Foo with control characters \'\\');
1277
        $this->schemaManager->dropAndCreateTable($table);
1278
1279
        $table = $this->schemaManager->listTableDetails('table_with_comment');
1280
        self::assertSame('Foo with control characters \'\\', $table->getComment());
1281
    }
1282
}
1283