Failed Conditions
Pull Request — master (#2929)
by Alexander
62:06
created

testAlterTableChangePrimaryKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 0
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional\Schema;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\DBAL\DBALException;
7
use Doctrine\DBAL\Events;
8
use Doctrine\DBAL\Platforms\OraclePlatform;
9
use Doctrine\DBAL\Schema\Column;
10
use Doctrine\DBAL\Schema\ColumnDiff;
11
use Doctrine\DBAL\Schema\Comparator;
12
use Doctrine\DBAL\Schema\SchemaDiff;
13
use Doctrine\DBAL\Schema\Sequence;
14
use Doctrine\DBAL\Schema\Table;
15
use Doctrine\DBAL\Schema\TableDiff;
16
use Doctrine\DBAL\Types\Type;
17
18
class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTestCase
19
{
20
    /**
21
     * @var \Doctrine\DBAL\Schema\AbstractSchemaManager
22
     */
23
    protected $_sm;
24
25
    protected function getPlatformName()
26
    {
27
        $class = get_class($this);
28
        $e = explode('\\', $class);
29
        $testClass = end($e);
30
        $dbms = strtolower(str_replace('SchemaManagerTest', null, $testClass));
31
        return $dbms;
32
    }
33
34
    protected function setUp()
35
    {
36
        parent::setUp();
37
38
        $dbms = $this->getPlatformName();
39
40
        if ($this->_conn->getDatabasePlatform()->getName() !== $dbms) {
41
            $this->markTestSkipped(get_class($this) . ' requires the use of ' . $dbms);
42
        }
43
44
        $this->_sm = $this->_conn->getSchemaManager();
45
    }
46
47
48
    protected function tearDown()
49
    {
50
        parent::tearDown();
51
52
        $this->_sm->tryMethod('dropTable', 'testschema.my_table_in_namespace');
53
54
        //TODO: SchemaDiff does not drop removed namespaces?
55
        try {
56
            //sql server versions below 2016 do not support 'IF EXISTS' so we have to catch the exception here
57
            $this->_conn->exec('DROP SCHEMA testschema');
58
        } catch (DBALException $e) {
59
            return;
60
        }
61
    }
62
63
64
    /**
65
     * @group DBAL-1220
66
     */
67
    public function testDropsDatabaseWithActiveConnections()
68
    {
69
        if (! $this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) {
70
            $this->markTestSkipped('Cannot drop Database client side with this Driver.');
71
        }
72
73
        $this->_sm->dropAndCreateDatabase('test_drop_database');
74
75
        $knownDatabases = $this->_sm->listDatabases();
76
        if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) {
77
            self::assertContains('TEST_DROP_DATABASE', $knownDatabases);
78
        } else {
79
            self::assertContains('test_drop_database', $knownDatabases);
80
        }
81
82
        $params = $this->_conn->getParams();
83
        if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) {
84
            $params['user'] = 'test_drop_database';
85
        } else {
86
            $params['dbname'] = 'test_drop_database';
87
        }
88
89
        $user = $params['user'] ?? null;
90
        $password = $params['password'] ?? null;
91
92
        $connection = $this->_conn->getDriver()->connect($params, $user, $password);
93
94
        self::assertInstanceOf('Doctrine\DBAL\Driver\Connection', $connection);
95
96
        $this->_sm->dropDatabase('test_drop_database');
97
98
        self::assertNotContains('test_drop_database', $this->_sm->listDatabases());
99
    }
100
101
    /**
102
     * @group DBAL-195
103
     */
104
    public function testDropAndCreateSequence()
105
    {
106
        if ( ! $this->_conn->getDatabasePlatform()->supportsSequences()) {
107
            $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.');
108
        }
109
110
        $name = 'dropcreate_sequences_test_seq';
111
112
        $this->_sm->dropAndCreateSequence(new \Doctrine\DBAL\Schema\Sequence($name, 20, 10));
113
114
        self::assertTrue($this->hasElementWithName($this->_sm->listSequences(), $name));
115
    }
116
117
    private function hasElementWithName(array $items, string $name) : bool
118
    {
119
        $filteredList = array_filter(
120
            $items,
121
            function (\Doctrine\DBAL\Schema\AbstractAsset $item) use ($name) : bool {
122
                return $item->getShortestName($item->getNamespaceName()) === $name;
123
            }
124
        );
125
126
        return count($filteredList) === 1;
127
    }
128
129
    public function testListSequences()
130
    {
131
        if(!$this->_conn->getDatabasePlatform()->supportsSequences()) {
132
            $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.');
133
        }
134
135
        $sequence = new \Doctrine\DBAL\Schema\Sequence('list_sequences_test_seq', 20, 10);
136
        $this->_sm->createSequence($sequence);
137
138
        $sequences = $this->_sm->listSequences();
139
140
        self::assertInternalType('array', $sequences, 'listSequences() should return an array.');
141
142
        $foundSequence = null;
143
        foreach($sequences as $sequence) {
144
            self::assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $sequence, 'Array elements of listSequences() should be Sequence instances.');
145
            if(strtolower($sequence->getName()) == 'list_sequences_test_seq') {
146
                $foundSequence = $sequence;
147
            }
148
        }
149
150
        self::assertNotNull($foundSequence, "Sequence with name 'list_sequences_test_seq' was not found.");
151
        self::assertEquals(20, $foundSequence->getAllocationSize(), "Allocation Size is expected to be 20.");
152
        self::assertEquals(10, $foundSequence->getInitialValue(), "Initial Value is expected to be 10.");
153
    }
154
155
    public function testListDatabases()
156
    {
157
        if (!$this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) {
158
            $this->markTestSkipped('Cannot drop Database client side with this Driver.');
159
        }
160
161
        $this->_sm->dropAndCreateDatabase('test_create_database');
162
        $databases = $this->_sm->listDatabases();
163
164
        $databases = array_map('strtolower', $databases);
165
166
        self::assertContains('test_create_database', $databases);
167
    }
168
169
    /**
170
     * @group DBAL-1058
171
     */
172
    public function testListNamespaceNames()
173
    {
174
        if (!$this->_sm->getDatabasePlatform()->supportsSchemas()) {
175
            $this->markTestSkipped('Platform does not support schemas.');
176
        }
177
178
        // Currently dropping schemas is not supported, so we have to workaround here.
179
        $namespaces = $this->_sm->listNamespaceNames();
180
        $namespaces = array_map('strtolower', $namespaces);
181
182
        if (!in_array('test_create_schema', $namespaces)) {
183
            $this->_conn->executeUpdate($this->_sm->getDatabasePlatform()->getCreateSchemaSQL('test_create_schema'));
184
185
            $namespaces = $this->_sm->listNamespaceNames();
186
            $namespaces = array_map('strtolower', $namespaces);
187
        }
188
189
        self::assertContains('test_create_schema', $namespaces);
190
    }
191
192
    public function testListTables()
193
    {
194
        $this->createTestTable('list_tables_test');
195
        $tables = $this->_sm->listTables();
196
197
        self::assertInternalType('array', $tables);
198
        self::assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'.");
199
200
        $foundTable = false;
201
        foreach ($tables as $table) {
202
            self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table);
203
            if (strtolower($table->getName()) == 'list_tables_test') {
204
                $foundTable = true;
205
206
                self::assertTrue($table->hasColumn('id'));
207
                self::assertTrue($table->hasColumn('test'));
208
                self::assertTrue($table->hasColumn('foreign_key_test'));
209
            }
210
        }
211
212
        self::assertTrue( $foundTable , "The 'list_tables_test' table has to be found.");
213
    }
214
215
    public function createListTableColumns()
216
    {
217
        $table = new Table('list_table_columns');
218
        $table->addColumn('id', 'integer', array('notnull' => true));
219
        $table->addColumn('test', 'string', array('length' => 255, 'notnull' => false, 'default' => 'expected default'));
220
        $table->addColumn('foo', 'text', array('notnull' => true));
221
        $table->addColumn('bar', 'decimal', array('precision' => 10, 'scale' => 4, 'notnull' => false));
222
        $table->addColumn('baz1', 'datetime');
223
        $table->addColumn('baz2', 'time');
224
        $table->addColumn('baz3', 'date');
225
        $table->setPrimaryKey(array('id'));
226
227
        return $table;
228
    }
229
230
    public function testListTableColumns()
231
    {
232
        $table = $this->createListTableColumns();
233
234
        $this->_sm->dropAndCreateTable($table);
235
236
        $columns = $this->_sm->listTableColumns('list_table_columns');
237
        $columnsKeys = array_keys($columns);
238
239
        self::assertArrayHasKey('id', $columns);
240
        self::assertEquals(0, array_search('id', $columnsKeys));
241
        self::assertEquals('id',   strtolower($columns['id']->getname()));
242
        self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['id']->gettype());
243
        self::assertEquals(false,  $columns['id']->getunsigned());
244
        self::assertEquals(true,   $columns['id']->getnotnull());
245
        self::assertEquals(null,   $columns['id']->getdefault());
246
        self::assertInternalType('array',  $columns['id']->getPlatformOptions());
247
248
        self::assertArrayHasKey('test', $columns);
249
        self::assertEquals(1, array_search('test', $columnsKeys));
250
        self::assertEquals('test', strtolower($columns['test']->getname()));
251
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['test']->gettype());
252
        self::assertEquals(255,    $columns['test']->getlength());
253
        self::assertEquals(false,  $columns['test']->getfixed());
254
        self::assertEquals(false,  $columns['test']->getnotnull());
255
        self::assertEquals('expected default',   $columns['test']->getdefault());
256
        self::assertInternalType('array',  $columns['test']->getPlatformOptions());
257
258
        self::assertEquals('foo',  strtolower($columns['foo']->getname()));
259
        self::assertEquals(2, array_search('foo', $columnsKeys));
260
        self::assertInstanceOf('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype());
261
        self::assertEquals(false,  $columns['foo']->getunsigned());
262
        self::assertEquals(false,  $columns['foo']->getfixed());
263
        self::assertEquals(true,   $columns['foo']->getnotnull());
264
        self::assertEquals(null,   $columns['foo']->getdefault());
265
        self::assertInternalType('array',  $columns['foo']->getPlatformOptions());
266
267
        self::assertEquals('bar',  strtolower($columns['bar']->getname()));
268
        self::assertEquals(3, array_search('bar', $columnsKeys));
269
        self::assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $columns['bar']->gettype());
270
        self::assertEquals(null,   $columns['bar']->getlength());
271
        self::assertEquals(10,     $columns['bar']->getprecision());
272
        self::assertEquals(4,      $columns['bar']->getscale());
273
        self::assertEquals(false,  $columns['bar']->getunsigned());
274
        self::assertEquals(false,  $columns['bar']->getfixed());
275
        self::assertEquals(false,  $columns['bar']->getnotnull());
276
        self::assertEquals(null,   $columns['bar']->getdefault());
277
        self::assertInternalType('array',  $columns['bar']->getPlatformOptions());
278
279
        self::assertEquals('baz1', strtolower($columns['baz1']->getname()));
280
        self::assertEquals(4, array_search('baz1', $columnsKeys));
281
        self::assertInstanceOf('Doctrine\DBAL\Types\DateTimeType', $columns['baz1']->gettype());
282
        self::assertEquals(true,   $columns['baz1']->getnotnull());
283
        self::assertEquals(null,   $columns['baz1']->getdefault());
284
        self::assertInternalType('array',  $columns['baz1']->getPlatformOptions());
285
286
        self::assertEquals('baz2', strtolower($columns['baz2']->getname()));
287
        self::assertEquals(5, array_search('baz2', $columnsKeys));
288
        self::assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime'));
289
        self::assertEquals(true,   $columns['baz2']->getnotnull());
290
        self::assertEquals(null,   $columns['baz2']->getdefault());
291
        self::assertInternalType('array',  $columns['baz2']->getPlatformOptions());
292
293
        self::assertEquals('baz3', strtolower($columns['baz3']->getname()));
294
        self::assertEquals(6, array_search('baz3', $columnsKeys));
295
        self::assertContains($columns['baz3']->gettype()->getName(), array('time', 'date', 'datetime'));
296
        self::assertEquals(true,   $columns['baz3']->getnotnull());
297
        self::assertEquals(null,   $columns['baz3']->getdefault());
298
        self::assertInternalType('array',  $columns['baz3']->getPlatformOptions());
299
    }
300
301
    /**
302
     * @group DBAL-1078
303
     */
304
    public function testListTableColumnsWithFixedStringColumn()
305
    {
306
        $tableName = 'test_list_table_fixed_string';
307
308
        $table = new Table($tableName);
309
        $table->addColumn('column_char', 'string', array('fixed' => true, 'length' => 2));
310
311
        $this->_sm->createTable($table);
312
313
        $columns = $this->_sm->listTableColumns($tableName);
314
315
        self::assertArrayHasKey('column_char', $columns);
316
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['column_char']->getType());
317
        self::assertTrue($columns['column_char']->getFixed());
318
        self::assertSame(2, $columns['column_char']->getLength());
319
    }
320
321
    public function testListTableColumnsDispatchEvent()
322
    {
323
        $table = $this->createListTableColumns();
324
325
        $this->_sm->dropAndCreateTable($table);
326
327
        $listenerMock = $this
328
            ->getMockBuilder('ListTableColumnsDispatchEventListener')
329
            ->setMethods(['onSchemaColumnDefinition'])
330
            ->getMock();
331
        $listenerMock
332
            ->expects($this->exactly(7))
333
            ->method('onSchemaColumnDefinition');
334
335
        $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager();
336
337
        $eventManager = new EventManager();
338
        $eventManager->addEventListener(array(Events::onSchemaColumnDefinition), $listenerMock);
339
340
        $this->_sm->getDatabasePlatform()->setEventManager($eventManager);
341
342
        $this->_sm->listTableColumns('list_table_columns');
343
344
        $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager);
345
    }
346
347
    public function testListTableIndexesDispatchEvent()
348
    {
349
        $table = $this->getTestTable('list_table_indexes_test');
350
        $table->addUniqueIndex(array('test'), 'test_index_name');
351
        $table->addIndex(array('id', 'test'), 'test_composite_idx');
352
353
        $this->_sm->dropAndCreateTable($table);
354
355
        $listenerMock = $this
356
            ->getMockBuilder('ListTableIndexesDispatchEventListener')
357
            ->setMethods(['onSchemaIndexDefinition'])
358
            ->getMock();
359
        $listenerMock
360
            ->expects($this->exactly(3))
361
            ->method('onSchemaIndexDefinition');
362
363
        $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager();
364
365
        $eventManager = new EventManager();
366
        $eventManager->addEventListener(array(Events::onSchemaIndexDefinition), $listenerMock);
367
368
        $this->_sm->getDatabasePlatform()->setEventManager($eventManager);
369
370
        $this->_sm->listTableIndexes('list_table_indexes_test');
371
372
        $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager);
373
    }
374
375
    public function testDiffListTableColumns()
376
    {
377
        if ($this->_sm->getDatabasePlatform()->getName() == 'oracle') {
378
            $this->markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).');
379
        }
380
381
        $offlineTable = $this->createListTableColumns();
382
        $this->_sm->dropAndCreateTable($offlineTable);
383
        $onlineTable = $this->_sm->listTableDetails('list_table_columns');
384
385
        $comparator = new \Doctrine\DBAL\Schema\Comparator();
386
        $diff = $comparator->diffTable($offlineTable, $onlineTable);
387
388
        self::assertFalse($diff, "No differences should be detected with the offline vs online schema.");
389
    }
390
391
    public function testListTableIndexes()
392
    {
393
        $table = $this->getTestCompositeTable('list_table_indexes_test');
394
        $table->addUniqueIndex(array('test'), 'test_index_name');
395
        $table->addIndex(array('id', 'test'), 'test_composite_idx');
396
397
        $this->_sm->dropAndCreateTable($table);
398
399
        $tableIndexes = $this->_sm->listTableIndexes('list_table_indexes_test');
400
401
        self::assertEquals(3, count($tableIndexes));
402
403
        self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
404
        self::assertEquals(array('id', 'other_id'), array_map('strtolower', $tableIndexes['primary']->getColumns()));
405
        self::assertTrue($tableIndexes['primary']->isUnique());
406
        self::assertTrue($tableIndexes['primary']->isPrimary());
407
408
        self::assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName()));
409
        self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns()));
410
        self::assertTrue($tableIndexes['test_index_name']->isUnique());
411
        self::assertFalse($tableIndexes['test_index_name']->isPrimary());
412
413
        self::assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName()));
414
        self::assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns()));
415
        self::assertFalse($tableIndexes['test_composite_idx']->isUnique());
416
        self::assertFalse($tableIndexes['test_composite_idx']->isPrimary());
417
    }
418
419
    public function testDropAndCreateIndex()
420
    {
421
        $table = $this->getTestTable('test_create_index');
422
        $table->addUniqueIndex(array('test'), 'test');
423
        $this->_sm->dropAndCreateTable($table);
424
425
        $this->_sm->dropAndCreateIndex($table->getIndex('test'), $table);
426
        $tableIndexes = $this->_sm->listTableIndexes('test_create_index');
427
        self::assertInternalType('array', $tableIndexes);
428
429
        self::assertEquals('test',        strtolower($tableIndexes['test']->getName()));
430
        self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test']->getColumns()));
431
        self::assertTrue($tableIndexes['test']->isUnique());
432
        self::assertFalse($tableIndexes['test']->isPrimary());
433
    }
434
435
    public function testCreateTableWithForeignKeys()
436
    {
437
        if(!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
438
            $this->markTestSkipped('Platform does not support foreign keys.');
439
        }
440
441
        $tableB = $this->getTestTable('test_foreign');
442
443
        $this->_sm->dropAndCreateTable($tableB);
444
445
        $tableA = $this->getTestTable('test_create_fk');
446
        $tableA->addForeignKeyConstraint('test_foreign', array('foreign_key_test'), array('id'));
447
448
        $this->_sm->dropAndCreateTable($tableA);
449
450
        $fkTable = $this->_sm->listTableDetails('test_create_fk');
451
        $fkConstraints = $fkTable->getForeignKeys();
452
        self::assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key.");
453
454
        $fkConstraint = current($fkConstraints);
455
        self::assertInstanceOf('\Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkConstraint);
456
        self::assertEquals('test_foreign',             strtolower($fkConstraint->getForeignTableName()));
457
        self::assertEquals(array('foreign_key_test'),  array_map('strtolower', $fkConstraint->getColumns()));
458
        self::assertEquals(array('id'),                array_map('strtolower', $fkConstraint->getForeignColumns()));
459
460
        self::assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), "The columns of a foreign key constraint should always be indexed.");
461
    }
462
463
    public function testListForeignKeys()
464
    {
465
        if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
466
            $this->markTestSkipped('Does not support foreign key constraints.');
467
        }
468
469
        $this->createTestTable('test_create_fk1');
470
        $this->createTestTable('test_create_fk2');
471
472
        $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
473
            array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onDelete' => 'CASCADE')
474
        );
475
476
        $this->_sm->createForeignKey($foreignKey, 'test_create_fk1');
477
478
        $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1');
479
480
        self::assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key.");
481
482
        self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
483
        self::assertEquals(array('foreign_key_test'),  array_map('strtolower', $fkeys[0]->getLocalColumns()));
484
        self::assertEquals(array('id'),                array_map('strtolower', $fkeys[0]->getForeignColumns()));
485
        self::assertEquals('test_create_fk2',          strtolower($fkeys[0]->getForeignTableName()));
486
487
        if($fkeys[0]->hasOption('onDelete')) {
488
            self::assertEquals('CASCADE', $fkeys[0]->getOption('onDelete'));
489
        }
490
    }
491
492
    protected function getCreateExampleViewSql()
493
    {
494
        $this->markTestSkipped('No Create Example View SQL was defined for this SchemaManager');
495
    }
496
497
    public function testCreateSchema()
498
    {
499
        $this->createTestTable('test_table');
500
501
        $schema = $this->_sm->createSchema();
502
        self::assertTrue($schema->hasTable('test_table'));
503
    }
504
505
    public function testAlterTableScenario()
506
    {
507
        if(!$this->_sm->getDatabasePlatform()->supportsAlterTable()) {
508
            $this->markTestSkipped('Alter Table is not supported by this platform.');
509
        }
510
511
        $alterTable = $this->createTestTable('alter_table');
512
        $this->createTestTable('alter_table_foreign');
513
514
        $table = $this->_sm->listTableDetails('alter_table');
515
        self::assertTrue($table->hasColumn('id'));
516
        self::assertTrue($table->hasColumn('test'));
517
        self::assertTrue($table->hasColumn('foreign_key_test'));
518
        self::assertEquals(0, count($table->getForeignKeys()));
519
        self::assertEquals(1, count($table->getIndexes()));
520
521
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
522
        $tableDiff->fromTable = $alterTable;
523
        $tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer'));
524
        $tableDiff->removedColumns['test'] = $table->getColumn('test');
525
526
        $this->_sm->alterTable($tableDiff);
527
528
        $table = $this->_sm->listTableDetails('alter_table');
529
        self::assertFalse($table->hasColumn('test'));
530
        self::assertTrue($table->hasColumn('foo'));
531
532
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
533
        $tableDiff->fromTable = $table;
534
        $tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo'));
535
536
        $this->_sm->alterTable($tableDiff);
537
538
        $table = $this->_sm->listTableDetails('alter_table');
539
        self::assertEquals(2, count($table->getIndexes()));
540
        self::assertTrue($table->hasIndex('foo_idx'));
541
        self::assertEquals(array('foo'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
542
        self::assertFalse($table->getIndex('foo_idx')->isPrimary());
543
        self::assertFalse($table->getIndex('foo_idx')->isUnique());
544
545
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
546
        $tableDiff->fromTable = $table;
547
        $tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test'));
548
549
        $this->_sm->alterTable($tableDiff);
550
551
        $table = $this->_sm->listTableDetails('alter_table');
552
        self::assertEquals(2, count($table->getIndexes()));
553
        self::assertTrue($table->hasIndex('foo_idx'));
554
        self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
555
556
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
557
        $tableDiff->fromTable = $table;
558
        $tableDiff->renamedIndexes['foo_idx'] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
559
560
        $this->_sm->alterTable($tableDiff);
561
562
        $table = $this->_sm->listTableDetails('alter_table');
563
        self::assertEquals(2, count($table->getIndexes()));
564
        self::assertTrue($table->hasIndex('bar_idx'));
565
        self::assertFalse($table->hasIndex('foo_idx'));
566
        self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('bar_idx')->getColumns()));
567
        self::assertFalse($table->getIndex('bar_idx')->isPrimary());
568
        self::assertFalse($table->getIndex('bar_idx')->isUnique());
569
570
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
571
        $tableDiff->fromTable = $table;
572
        $tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
573
        $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id'));
574
        $tableDiff->addedForeignKeys[] = $fk;
575
576
        $this->_sm->alterTable($tableDiff);
577
        $table = $this->_sm->listTableDetails('alter_table');
578
579
        // dont check for index size here, some platforms automatically add indexes for foreign keys.
580
        self::assertFalse($table->hasIndex('bar_idx'));
581
582
        if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
583
            $fks = $table->getForeignKeys();
584
            self::assertCount(1, $fks);
585
            $foreignKey = current($fks);
586
            self::assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName()));
587
            self::assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns()));
588
            self::assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns()));
589
        }
590
    }
591
592
593
    public function testTableInNamespace()
594
    {
595
        if (! $this->_sm->getDatabasePlatform()->supportsSchemas()) {
596
            $this->markTestSkipped('Schema definition is not supported by this platform.');
597
        }
598
599
        //create schema
600
        $diff                  = new SchemaDiff();
601
        $diff->newNamespaces[] = 'testschema';
602
603
        foreach ($diff->toSql($this->_sm->getDatabasePlatform()) as $sql) {
604
            $this->_conn->exec($sql);
605
        }
606
607
        //test if table is create in namespace
608
        $this->createTestTable('testschema.my_table_in_namespace');
609
        self::assertContains('testschema.my_table_in_namespace', $this->_sm->listTableNames());
610
611
        //tables without namespace should be created in default namespace
612
        //default namespaces are ignored in table listings
613
        $this->createTestTable('my_table_not_in_namespace');
614
        self::assertContains('my_table_not_in_namespace', $this->_sm->listTableNames());
615
    }
616
617
    public function testCreateAndListViews()
618
    {
619
        if (!$this->_sm->getDatabasePlatform()->supportsViews()) {
620
            $this->markTestSkipped('Views is not supported by this platform.');
621
        }
622
623
        $this->createTestTable('view_test_table');
624
625
        $name = "doctrine_test_view";
626
        $sql = "SELECT * FROM view_test_table";
627
628
        $view = new \Doctrine\DBAL\Schema\View($name, $sql);
629
630
        $this->_sm->dropAndCreateView($view);
631
632
        self::assertTrue($this->hasElementWithName($this->_sm->listViews(), $name));
633
    }
634
635
    public function testAutoincrementDetection()
636
    {
637
        if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) {
638
            $this->markTestSkipped('This test is only supported on platforms that have autoincrement');
639
        }
640
641
        $table = new Table('test_autoincrement');
642
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
643
        $table->addColumn('id', 'integer', array('autoincrement' => true));
644
        $table->setPrimaryKey(array('id'));
645
646
        $this->_sm->createTable($table);
647
648
        $inferredTable = $this->_sm->listTableDetails('test_autoincrement');
649
        self::assertTrue($inferredTable->hasColumn('id'));
650
        self::assertTrue($inferredTable->getColumn('id')->getAutoincrement());
651
    }
652
653
    /**
654
     * @group DBAL-792
655
     */
656
    public function testAutoincrementDetectionMulticolumns()
657
    {
658
        if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) {
659
            $this->markTestSkipped('This test is only supported on platforms that have autoincrement');
660
        }
661
662
        $table = new Table('test_not_autoincrement');
663
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
664
        $table->addColumn('id', 'integer');
665
        $table->addColumn('other_id', 'integer');
666
        $table->setPrimaryKey(array('id', 'other_id'));
667
668
        $this->_sm->createTable($table);
669
670
        $inferredTable = $this->_sm->listTableDetails('test_not_autoincrement');
671
        self::assertTrue($inferredTable->hasColumn('id'));
672
        self::assertFalse($inferredTable->getColumn('id')->getAutoincrement());
673
    }
674
675
    /**
676
     * @group DDC-887
677
     */
678
    public function testUpdateSchemaWithForeignKeyRenaming()
679
    {
680
        if (!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
681
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
682
        }
683
684
        $table = new Table('test_fk_base');
685
        $table->addColumn('id', 'integer');
686
        $table->setPrimaryKey(array('id'));
687
688
        $tableFK = new Table('test_fk_rename');
689
        $tableFK->setSchemaConfig($this->_sm->createSchemaConfig());
690
        $tableFK->addColumn('id', 'integer');
691
        $tableFK->addColumn('fk_id', 'integer');
692
        $tableFK->setPrimaryKey(array('id'));
693
        $tableFK->addIndex(array('fk_id'), 'fk_idx');
694
        $tableFK->addForeignKeyConstraint('test_fk_base', array('fk_id'), array('id'));
695
696
        $this->_sm->createTable($table);
697
        $this->_sm->createTable($tableFK);
698
699
        $tableFKNew = new Table('test_fk_rename');
700
        $tableFKNew->setSchemaConfig($this->_sm->createSchemaConfig());
701
        $tableFKNew->addColumn('id', 'integer');
702
        $tableFKNew->addColumn('rename_fk_id', 'integer');
703
        $tableFKNew->setPrimaryKey(array('id'));
704
        $tableFKNew->addIndex(array('rename_fk_id'), 'fk_idx');
705
        $tableFKNew->addForeignKeyConstraint('test_fk_base', array('rename_fk_id'), array('id'));
706
707
        $c = new \Doctrine\DBAL\Schema\Comparator();
708
        $tableDiff = $c->diffTable($tableFK, $tableFKNew);
709
710
        $this->_sm->alterTable($tableDiff);
0 ignored issues
show
Bug introduced by
It seems like $tableDiff can also be of type false; however, parameter $tableDiff of Doctrine\DBAL\Schema\Abs...maManager::alterTable() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

710
        $this->_sm->alterTable(/** @scrutinizer ignore-type */ $tableDiff);
Loading history...
711
712
        $table       = $this->_sm->listTableDetails('test_fk_rename');
713
        $foreignKeys = $table->getForeignKeys();
714
715
        self::assertTrue($table->hasColumn('rename_fk_id'));
716
        self::assertCount(1, $foreignKeys);
717
        self::assertSame(['rename_fk_id'], array_map('strtolower', current($foreignKeys)->getColumns()));
718
    }
719
720
    /**
721
     * @group DBAL-1062
722
     */
723
    public function testRenameIndexUsedInForeignKeyConstraint()
724
    {
725
        if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
726
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
727
        }
728
729
        $primaryTable = new Table('test_rename_index_primary');
730
        $primaryTable->addColumn('id', 'integer');
731
        $primaryTable->setPrimaryKey(array('id'));
732
733
        $foreignTable = new Table('test_rename_index_foreign');
734
        $foreignTable->addColumn('fk', 'integer');
735
        $foreignTable->addIndex(array('fk'), 'rename_index_fk_idx');
736
        $foreignTable->addForeignKeyConstraint(
737
            'test_rename_index_primary',
738
            array('fk'),
739
            array('id'),
740
            array(),
741
            'fk_constraint'
742
        );
743
744
        $this->_sm->dropAndCreateTable($primaryTable);
745
        $this->_sm->dropAndCreateTable($foreignTable);
746
747
        $foreignTable2 = clone $foreignTable;
748
        $foreignTable2->renameIndex('rename_index_fk_idx', 'renamed_index_fk_idx');
749
750
        $comparator = new Comparator();
751
752
        $this->_sm->alterTable($comparator->diffTable($foreignTable, $foreignTable2));
0 ignored issues
show
Bug introduced by
It seems like $comparator->diffTable($...nTable, $foreignTable2) can also be of type false; however, parameter $tableDiff of Doctrine\DBAL\Schema\Abs...maManager::alterTable() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

752
        $this->_sm->alterTable(/** @scrutinizer ignore-type */ $comparator->diffTable($foreignTable, $foreignTable2));
Loading history...
753
754
        $foreignTable = $this->_sm->listTableDetails('test_rename_index_foreign');
755
756
        self::assertFalse($foreignTable->hasIndex('rename_index_fk_idx'));
757
        self::assertTrue($foreignTable->hasIndex('renamed_index_fk_idx'));
758
        self::assertTrue($foreignTable->hasForeignKey('fk_constraint'));
759
    }
760
761
    /**
762
     * @group DBAL-42
763
     */
764
    public function testGetColumnComment()
765
    {
766
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
767
             ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
768
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
769
            $this->markTestSkipped('Database does not support column comments.');
770
        }
771
772
        $table = new Table('column_comment_test');
773
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
774
        $table->setPrimaryKey(array('id'));
775
776
        $this->_sm->createTable($table);
777
778
        $columns = $this->_sm->listTableColumns("column_comment_test");
779
        self::assertEquals(1, count($columns));
780
        self::assertEquals('This is a comment', $columns['id']->getComment());
781
782
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('column_comment_test');
783
        $tableDiff->fromTable = $table;
784
        $tableDiff->changedColumns['id'] = new \Doctrine\DBAL\Schema\ColumnDiff(
785
            'id', new \Doctrine\DBAL\Schema\Column(
786
                'id', \Doctrine\DBAL\Types\Type::getType('integer')
787
            ),
788
            array('comment'),
789
            new \Doctrine\DBAL\Schema\Column(
790
                'id', \Doctrine\DBAL\Types\Type::getType('integer'), array('comment' => 'This is a comment')
791
            )
792
        );
793
794
        $this->_sm->alterTable($tableDiff);
795
796
        $columns = $this->_sm->listTableColumns("column_comment_test");
797
        self::assertEquals(1, count($columns));
798
        self::assertEmpty($columns['id']->getComment());
799
    }
800
801
    /**
802
     * @group DBAL-42
803
     */
804
    public function testAutomaticallyAppendCommentOnMarkedColumns()
805
    {
806
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
807
             ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
808
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
809
            $this->markTestSkipped('Database does not support column comments.');
810
        }
811
812
        $table = new Table('column_comment_test2');
813
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
814
        $table->addColumn('obj', 'object', array('comment' => 'This is a comment'));
815
        $table->addColumn('arr', 'array', array('comment' => 'This is a comment'));
816
        $table->setPrimaryKey(array('id'));
817
818
        $this->_sm->createTable($table);
819
820
        $columns = $this->_sm->listTableColumns("column_comment_test2");
821
        self::assertEquals(3, count($columns));
822
        self::assertEquals('This is a comment', $columns['id']->getComment());
823
        self::assertEquals('This is a comment', $columns['obj']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
824
        self::assertInstanceOf('Doctrine\DBAL\Types\ObjectType', $columns['obj']->getType(), "The Doctrine2 should be detected from comment hint.");
825
        self::assertEquals('This is a comment', $columns['arr']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
826
        self::assertInstanceOf('Doctrine\DBAL\Types\ArrayType', $columns['arr']->getType(), "The Doctrine2 should be detected from comment hint.");
827
    }
828
829
    /**
830
     * @group DBAL-1228
831
     */
832
    public function testCommentHintOnDateIntervalTypeColumn()
833
    {
834
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
835
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
836
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
837
            $this->markTestSkipped('Database does not support column comments.');
838
        }
839
840
        $table = new Table('column_dateinterval_comment');
841
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
842
        $table->addColumn('date_interval', 'dateinterval', array('comment' => 'This is a comment'));
843
        $table->setPrimaryKey(array('id'));
844
845
        $this->_sm->createTable($table);
846
847
        $columns = $this->_sm->listTableColumns("column_dateinterval_comment");
848
        self::assertEquals(2, count($columns));
849
        self::assertEquals('This is a comment', $columns['id']->getComment());
850
        self::assertEquals('This is a comment', $columns['date_interval']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
851
        self::assertInstanceOf('Doctrine\DBAL\Types\DateIntervalType', $columns['date_interval']->getType(), "The Doctrine2 should be detected from comment hint.");
852
    }
853
854
    /**
855
     * @group DBAL-825
856
     */
857
    public function testChangeColumnsTypeWithDefaultValue()
858
    {
859
        $tableName = 'column_def_change_type';
860
        $table     = new Table($tableName);
861
862
        $table->addColumn('col_int', 'smallint', array('default' => 666));
863
        $table->addColumn('col_string', 'string', array('default' => 'foo'));
864
865
        $this->_sm->dropAndCreateTable($table);
866
867
        $tableDiff = new TableDiff($tableName);
868
        $tableDiff->fromTable = $table;
869
        $tableDiff->changedColumns['col_int'] = new ColumnDiff(
870
            'col_int',
871
            new Column('col_int', Type::getType('integer'), array('default' => 666)),
872
            array('type'),
873
            new Column('col_int', Type::getType('smallint'), array('default' => 666))
874
        );
875
876
        $tableDiff->changedColumns['col_string'] = new ColumnDiff(
877
            'col_string',
878
            new Column('col_string', Type::getType('string'), array('default' => 'foo', 'fixed' => true)),
879
            array('fixed'),
880
            new Column('col_string', Type::getType('string'), array('default' => 'foo'))
881
        );
882
883
        $this->_sm->alterTable($tableDiff);
884
885
        $columns = $this->_sm->listTableColumns($tableName);
886
887
        self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['col_int']->getType());
888
        self::assertEquals(666, $columns['col_int']->getDefault());
889
890
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['col_string']->getType());
891
        self::assertEquals('foo', $columns['col_string']->getDefault());
892
    }
893
894
    /**
895
     * @group DBAL-197
896
     */
897
    public function testListTableWithBlob()
898
    {
899
        $table = new Table('test_blob_table');
900
        $table->addColumn('id', 'integer', ['comment' => 'This is a comment']);
901
        $table->addColumn('binarydata', 'blob', []);
902
        $table->setPrimaryKey(['id']);
903
904
        $this->_sm->createTable($table);
905
906
        $created = $this->_sm->listTableDetails('test_blob_table');
907
908
        self::assertTrue($created->hasColumn('id'));
909
        self::assertTrue($created->hasColumn('binarydata'));
910
        self::assertTrue($created->hasPrimaryKey());
911
    }
912
913
    /**
914
     * @param string $name
915
     * @param array  $data
916
     * @return Table
917
     */
918
    protected function createTestTable($name = 'test_table', $data = array())
919
    {
920
        $options = $data['options'] ?? [];
921
922
        $table = $this->getTestTable($name, $options);
923
924
        $this->_sm->dropAndCreateTable($table);
925
926
        return $table;
927
    }
928
929
    protected function getTestTable($name, $options=array())
930
    {
931
        $table = new Table($name, array(), array(), array(), false, $options);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $idGeneratorType of Doctrine\DBAL\Schema\Table::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

931
        $table = new Table($name, array(), array(), array(), /** @scrutinizer ignore-type */ false, $options);
Loading history...
932
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
933
        $table->addColumn('id', 'integer', array('notnull' => true));
934
        $table->setPrimaryKey(array('id'));
935
        $table->addColumn('test', 'string', array('length' => 255));
936
        $table->addColumn('foreign_key_test', 'integer');
937
        return $table;
938
    }
939
940
    protected function getTestCompositeTable($name)
941
    {
942
        $table = new Table($name, array(), array(), array(), false, array());
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $idGeneratorType of Doctrine\DBAL\Schema\Table::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

942
        $table = new Table($name, array(), array(), array(), /** @scrutinizer ignore-type */ false, array());
Loading history...
943
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
944
        $table->addColumn('id', 'integer', array('notnull' => true));
945
        $table->addColumn('other_id', 'integer', array('notnull' => true));
946
        $table->setPrimaryKey(array('id', 'other_id'));
947
        $table->addColumn('test', 'string', array('length' => 255));
948
        return $table;
949
    }
950
951
    protected function assertHasTable($tables, $tableName)
0 ignored issues
show
Unused Code introduced by
The parameter $tableName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

951
    protected function assertHasTable($tables, /** @scrutinizer ignore-unused */ $tableName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
952
    {
953
        $foundTable = false;
954
        foreach ($tables as $table) {
955
            self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.');
956
            if (strtolower($table->getName()) == 'list_tables_test_new_name') {
957
                $foundTable = true;
958
            }
959
        }
960
        self::assertTrue($foundTable, "Could not find new table");
961
    }
962
963
    public function testListForeignKeysComposite()
964
    {
965
        if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
966
            $this->markTestSkipped('Does not support foreign key constraints.');
967
        }
968
969
        $this->_sm->createTable($this->getTestTable('test_create_fk3'));
970
        $this->_sm->createTable($this->getTestCompositeTable('test_create_fk4'));
971
972
        $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
973
            array('id', 'foreign_key_test'), 'test_create_fk4', array('id', 'other_id'), 'foreign_key_test_fk2'
974
        );
975
976
        $this->_sm->createForeignKey($foreignKey, 'test_create_fk3');
977
978
        $fkeys = $this->_sm->listTableForeignKeys('test_create_fk3');
979
980
        self::assertEquals(1, count($fkeys), "Table 'test_create_fk3' has to have one foreign key.");
981
982
        self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
983
        self::assertEquals(array('id', 'foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns()));
984
        self::assertEquals(array('id', 'other_id'),         array_map('strtolower', $fkeys[0]->getForeignColumns()));
985
    }
986
987
    /**
988
     * @group DBAL-44
989
     */
990
    public function testColumnDefaultLifecycle()
991
    {
992
        $table = new Table("col_def_lifecycle");
993
        $table->addColumn('id', 'integer', array('autoincrement' => true));
994
        $table->addColumn('column1', 'string', array('default' => null));
995
        $table->addColumn('column2', 'string', array('default' => false));
996
        $table->addColumn('column3', 'string', array('default' => true));
997
        $table->addColumn('column4', 'string', array('default' => 0));
998
        $table->addColumn('column5', 'string', array('default' => ''));
999
        $table->addColumn('column6', 'string', array('default' => 'def'));
1000
        $table->addColumn('column7', 'integer', array('default' => 0));
1001
        $table->setPrimaryKey(array('id'));
1002
1003
        $this->_sm->dropAndCreateTable($table);
1004
1005
        $columns = $this->_sm->listTableColumns('col_def_lifecycle');
1006
1007
        self::assertNull($columns['id']->getDefault());
1008
        self::assertNull($columns['column1']->getDefault());
1009
        self::assertSame('', $columns['column2']->getDefault());
1010
        self::assertSame('1', $columns['column3']->getDefault());
1011
        self::assertSame('0', $columns['column4']->getDefault());
1012
        self::assertSame('', $columns['column5']->getDefault());
1013
        self::assertSame('def', $columns['column6']->getDefault());
1014
        self::assertSame('0', $columns['column7']->getDefault());
1015
1016
        $diffTable = clone $table;
1017
1018
        $diffTable->changeColumn('column1', array('default' => false));
1019
        $diffTable->changeColumn('column2', array('default' => null));
1020
        $diffTable->changeColumn('column3', array('default' => false));
1021
        $diffTable->changeColumn('column4', array('default' => null));
1022
        $diffTable->changeColumn('column5', array('default' => false));
1023
        $diffTable->changeColumn('column6', array('default' => 666));
1024
        $diffTable->changeColumn('column7', array('default' => null));
1025
1026
        $comparator = new Comparator();
1027
1028
        $this->_sm->alterTable($comparator->diffTable($table, $diffTable));
1029
1030
        $columns = $this->_sm->listTableColumns('col_def_lifecycle');
1031
1032
        self::assertSame('', $columns['column1']->getDefault());
1033
        self::assertNull($columns['column2']->getDefault());
1034
        self::assertSame('', $columns['column3']->getDefault());
1035
        self::assertNull($columns['column4']->getDefault());
1036
        self::assertSame('', $columns['column5']->getDefault());
1037
        self::assertSame('666', $columns['column6']->getDefault());
1038
        self::assertNull($columns['column7']->getDefault());
1039
    }
1040
1041
    public function testListTableWithBinary()
1042
    {
1043
        $tableName = 'test_binary_table';
1044
1045
        $table = new Table($tableName);
1046
        $table->addColumn('id', 'integer');
1047
        $table->addColumn('column_varbinary', 'binary', array());
1048
        $table->addColumn('column_binary', 'binary', array('fixed' => true));
1049
        $table->setPrimaryKey(array('id'));
1050
1051
        $this->_sm->createTable($table);
1052
1053
        $table = $this->_sm->listTableDetails($tableName);
1054
1055
        self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_varbinary')->getType());
1056
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
1057
1058
        self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_binary')->getType());
1059
        self::assertTrue($table->getColumn('column_binary')->getFixed());
1060
    }
1061
1062
    public function testListTableDetailsWithFullQualifiedTableName()
1063
    {
1064
        if ( ! $this->_sm->getDatabasePlatform()->supportsSchemas()) {
1065
            $this->markTestSkipped('Test only works on platforms that support schemas.');
1066
        }
1067
1068
        $defaultSchemaName = $this->_sm->getDatabasePlatform()->getDefaultSchemaName();
1069
        $primaryTableName  = 'primary_table';
1070
        $foreignTableName  = 'foreign_table';
1071
1072
        $table = new Table($foreignTableName);
1073
        $table->addColumn('id', 'integer', array('autoincrement' => true));
1074
        $table->setPrimaryKey(array('id'));
1075
1076
        $this->_sm->dropAndCreateTable($table);
1077
1078
        $table = new Table($primaryTableName);
1079
        $table->addColumn('id', 'integer', array('autoincrement' => true));
1080
        $table->addColumn('foo', 'integer');
1081
        $table->addColumn('bar', 'string');
1082
        $table->addForeignKeyConstraint($foreignTableName, array('foo'), array('id'));
1083
        $table->addIndex(array('bar'));
1084
        $table->setPrimaryKey(array('id'));
1085
1086
        $this->_sm->dropAndCreateTable($table);
1087
1088
        self::assertEquals(
1089
            $this->_sm->listTableColumns($primaryTableName),
1090
            $this->_sm->listTableColumns($defaultSchemaName . '.' . $primaryTableName)
1091
        );
1092
        self::assertEquals(
1093
            $this->_sm->listTableIndexes($primaryTableName),
1094
            $this->_sm->listTableIndexes($defaultSchemaName . '.' . $primaryTableName)
1095
        );
1096
        self::assertEquals(
1097
            $this->_sm->listTableForeignKeys($primaryTableName),
1098
            $this->_sm->listTableForeignKeys($defaultSchemaName . '.' . $primaryTableName)
1099
        );
1100
    }
1101
1102
    public function testCommentStringsAreQuoted()
1103
    {
1104
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
1105
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
1106
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
1107
            $this->markTestSkipped('Database does not support column comments.');
1108
        }
1109
1110
        $table = new Table('my_table');
1111
        $table->addColumn('id', 'integer', array('comment' => "It's a comment with a quote"));
1112
        $table->setPrimaryKey(array('id'));
1113
1114
        $this->_sm->createTable($table);
1115
1116
        $columns = $this->_sm->listTableColumns("my_table");
1117
        self::assertEquals("It's a comment with a quote", $columns['id']->getComment());
1118
    }
1119
1120
    public function testCommentNotDuplicated()
1121
    {
1122
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments()) {
1123
            $this->markTestSkipped('Database does not support column comments.');
1124
        }
1125
1126
        $options = array(
1127
            'type' => Type::getType('integer'),
1128
            'default' => 0,
1129
            'notnull' => true,
1130
            'comment' => 'expected+column+comment',
1131
        );
1132
        $columnDefinition = substr($this->_conn->getDatabasePlatform()->getColumnDeclarationSQL('id', $options), strlen('id') + 1);
1133
1134
        $table = new Table('my_table');
1135
        $table->addColumn('id', 'integer', array('columnDefinition' => $columnDefinition, 'comment' => 'unexpected_column_comment'));
1136
        $sql = $this->_conn->getDatabasePlatform()->getCreateTableSQL($table);
1137
1138
        self::assertContains('expected+column+comment', $sql[0]);
1139
        self::assertNotContains('unexpected_column_comment', $sql[0]);
1140
    }
1141
1142
    /**
1143
     * @group DBAL-1009
1144
     *
1145
     * @dataProvider getAlterColumnComment
1146
     */
1147
    public function testAlterColumnComment($comment1, $expectedComment1, $comment2, $expectedComment2)
1148
    {
1149
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
1150
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
1151
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
1152
            $this->markTestSkipped('Database does not support column comments.');
1153
        }
1154
1155
        $offlineTable = new Table('alter_column_comment_test');
1156
        $offlineTable->addColumn('comment1', 'integer', array('comment' => $comment1));
1157
        $offlineTable->addColumn('comment2', 'integer', array('comment' => $comment2));
1158
        $offlineTable->addColumn('no_comment1', 'integer');
1159
        $offlineTable->addColumn('no_comment2', 'integer');
1160
        $this->_sm->dropAndCreateTable($offlineTable);
1161
1162
        $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test");
1163
1164
        self::assertSame($expectedComment1, $onlineTable->getColumn('comment1')->getComment());
1165
        self::assertSame($expectedComment2, $onlineTable->getColumn('comment2')->getComment());
1166
        self::assertNull($onlineTable->getColumn('no_comment1')->getComment());
1167
        self::assertNull($onlineTable->getColumn('no_comment2')->getComment());
1168
1169
        $onlineTable->changeColumn('comment1', array('comment' => $comment2));
1170
        $onlineTable->changeColumn('comment2', array('comment' => $comment1));
1171
        $onlineTable->changeColumn('no_comment1', array('comment' => $comment1));
1172
        $onlineTable->changeColumn('no_comment2', array('comment' => $comment2));
1173
1174
        $comparator = new Comparator();
1175
1176
        $tableDiff = $comparator->diffTable($offlineTable, $onlineTable);
1177
1178
        self::assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
1179
1180
        $this->_sm->alterTable($tableDiff);
1181
1182
        $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test");
1183
1184
        self::assertSame($expectedComment2, $onlineTable->getColumn('comment1')->getComment());
1185
        self::assertSame($expectedComment1, $onlineTable->getColumn('comment2')->getComment());
1186
        self::assertSame($expectedComment1, $onlineTable->getColumn('no_comment1')->getComment());
1187
        self::assertSame($expectedComment2, $onlineTable->getColumn('no_comment2')->getComment());
1188
    }
1189
1190
    public function getAlterColumnComment()
1191
    {
1192
        return array(
1193
            array(null, null, ' ', ' '),
1194
            array(null, null, '0', '0'),
1195
            array(null, null, 'foo', 'foo'),
1196
1197
            array('', null, ' ', ' '),
1198
            array('', null, '0', '0'),
1199
            array('', null, 'foo', 'foo'),
1200
1201
            array(' ', ' ', '0', '0'),
1202
            array(' ', ' ', 'foo', 'foo'),
1203
1204
            array('0', '0', 'foo', 'foo'),
1205
        );
1206
    }
1207
1208
    /**
1209
     * @group DBAL-1095
1210
     */
1211
    public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys()
1212
    {
1213
        if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
1214
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
1215
        }
1216
1217
        $primaryTable = new Table('test_list_index_impl_primary');
1218
        $primaryTable->addColumn('id', 'integer');
1219
        $primaryTable->setPrimaryKey(array('id'));
1220
1221
        $foreignTable = new Table('test_list_index_impl_foreign');
1222
        $foreignTable->addColumn('fk1', 'integer');
1223
        $foreignTable->addColumn('fk2', 'integer');
1224
        $foreignTable->addIndex(array('fk1'), 'explicit_fk1_idx');
1225
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk1'), array('id'));
1226
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk2'), array('id'));
1227
1228
        $this->_sm->dropAndCreateTable($primaryTable);
1229
        $this->_sm->dropAndCreateTable($foreignTable);
1230
1231
        $indexes = $this->_sm->listTableIndexes('test_list_index_impl_foreign');
1232
1233
        self::assertCount(2, $indexes);
1234
        self::assertArrayHasKey('explicit_fk1_idx', $indexes);
1235
        self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes);
1236
    }
1237
1238
    /**
1239
     * @after
1240
     */
1241
    public function removeJsonArrayTable() : void
1242
    {
1243
        if ($this->_sm->tablesExist(['json_array_test'])) {
1244
            $this->_sm->dropTable('json_array_test');
1245
        }
1246
    }
1247
1248
    /**
1249
     * @group 2782
1250
     * @group 6654
1251
     */
1252
    public function testComparatorShouldReturnFalseWhenLegacyJsonArrayColumnHasComment() : void
1253
    {
1254
        $table = new Table('json_array_test');
1255
        $table->addColumn('parameters', 'json_array');
1256
1257
        $this->_sm->createTable($table);
1258
1259
        $comparator = new Comparator();
1260
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1261
1262
        self::assertFalse($tableDiff);
1263
    }
1264
1265
    /**
1266
     * @group 2782
1267
     * @group 6654
1268
     */
1269
    public function testComparatorShouldModifyOnlyTheCommentWhenUpdatingFromJsonArrayTypeOnLegacyPlatforms() : void
1270
    {
1271
        if ($this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1272
            $this->markTestSkipped('This test is only supported on platforms that do not have native JSON type.');
1273
        }
1274
1275
        $table = new Table('json_array_test');
1276
        $table->addColumn('parameters', 'json_array');
1277
1278
        $this->_sm->createTable($table);
1279
1280
        $table = new Table('json_array_test');
1281
        $table->addColumn('parameters', 'json');
1282
1283
        $comparator = new Comparator();
1284
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1285
1286
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1287
1288
        $changedColumn = $tableDiff->changedColumns['parameters'] ?? $tableDiff->changedColumns['PARAMETERS'];
1289
1290
        self::assertSame(['comment'], $changedColumn->changedProperties);
1291
    }
1292
1293
    /**
1294
     * @group 2782
1295
     * @group 6654
1296
     */
1297
    public function testComparatorShouldAddCommentToLegacyJsonArrayTypeThatDoesNotHaveIt() : void
1298
    {
1299
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1300
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1301
        }
1302
1303
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON NOT NULL)');
1304
1305
        $table = new Table('json_array_test');
1306
        $table->addColumn('parameters', 'json_array');
1307
1308
        $comparator = new Comparator();
1309
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1310
1311
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1312
        self::assertSame(['comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1313
    }
1314
1315
    /**
1316
     * @group 2782
1317
     * @group 6654
1318
     */
1319
    public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayType() : void
1320
    {
1321
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1322
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1323
        }
1324
1325
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)');
1326
1327
        $table = new Table('json_array_test');
1328
        $table->addColumn('parameters', 'json_array');
1329
1330
        $comparator = new Comparator();
1331
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1332
1333
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1334
        self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1335
    }
1336
1337
    /**
1338
     * @group 2782
1339
     * @group 6654
1340
     */
1341
    public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayTypeEvenWhenPlatformHasJsonSupport() : void
1342
    {
1343
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1344
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1345
        }
1346
1347
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)');
1348
1349
        $table = new Table('json_array_test');
1350
        $table->addColumn('parameters', 'json_array');
1351
1352
        $comparator = new Comparator();
1353
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1354
1355
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1356
        self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1357
    }
1358
1359
    /**
1360
     * @group 2782
1361
     * @group 6654
1362
     */
1363
    public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNow() : void
1364
    {
1365
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1366
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1367
        }
1368
1369
        $this->_conn->executeQuery('CREATE TABLE json_test (parameters JSON NOT NULL)');
1370
1371
        $table = new Table('json_test');
1372
        $table->addColumn('parameters', 'json');
1373
1374
        $comparator = new Comparator();
1375
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_test'), $table);
1376
1377
        self::assertFalse($tableDiff);
1378
    }
1379
1380
    /**
1381
     * @dataProvider commentsProvider
1382
     *
1383
     * @group 2596
1384
     */
1385
    public function testExtractDoctrineTypeFromComment(string $comment, string $expected, string $currentType) : void
1386
    {
1387
        $result = $this->_sm->extractDoctrineTypeFromComment($comment, $currentType);
1388
1389
        self::assertSame($expected, $result);
1390
    }
1391
1392
    public function commentsProvider() : array
1393
    {
1394
        $currentType = 'current type';
1395
1396
        return [
1397
            'invalid custom type comments'      => ['should.return.current.type', $currentType, $currentType],
1398
            'valid doctrine type'               => ['(DC2Type:guid)', 'guid', $currentType],
1399
            'valid with dots'                   => ['(DC2Type:type.should.return)', 'type.should.return', $currentType],
1400
            'valid with namespace'              => ['(DC2Type:Namespace\Class)', 'Namespace\Class', $currentType],
1401
            'valid with extra closing bracket'  => ['(DC2Type:should.stop)).before)', 'should.stop', $currentType],
1402
            'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop', $currentType],
1403
        ];
1404
    }
1405
1406
    public function testCreateAndListSequences() : void
1407
    {
1408
        if ( ! $this->_sm->getDatabasePlatform()->supportsSequences()) {
1409
            self::markTestSkipped('This test is only supported on platforms that support sequences.');
1410
        }
1411
1412
        $sequence1Name           = 'sequence_1';
1413
        $sequence1AllocationSize = 1;
1414
        $sequence1InitialValue   = 2;
1415
        $sequence2Name           = 'sequence_2';
1416
        $sequence2AllocationSize = 3;
1417
        $sequence2InitialValue   = 4;
1418
        $sequence1               = new Sequence($sequence1Name, $sequence1AllocationSize, $sequence1InitialValue);
1419
        $sequence2               = new Sequence($sequence2Name, $sequence2AllocationSize, $sequence2InitialValue);
1420
1421
        $this->_sm->createSequence($sequence1);
1422
        $this->_sm->createSequence($sequence2);
1423
1424
        /** @var Sequence[] $actualSequences */
1425
        $actualSequences = [];
1426
        foreach ($this->_sm->listSequences() as $sequence) {
1427
            $actualSequences[$sequence->getName()] = $sequence;
1428
        }
1429
1430
        $actualSequence1 = $actualSequences[$sequence1Name];
1431
        $actualSequence2 = $actualSequences[$sequence2Name];
1432
1433
        self::assertSame($sequence1Name, $actualSequence1->getName());
1434
        self::assertEquals($sequence1AllocationSize, $actualSequence1->getAllocationSize());
1435
        self::assertEquals($sequence1InitialValue, $actualSequence1->getInitialValue());
1436
1437
        self::assertSame($sequence2Name, $actualSequence2->getName());
1438
        self::assertEquals($sequence2AllocationSize, $actualSequence2->getAllocationSize());
1439
        self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue());
1440
    }
1441
1442
    /**
1443
     * @group 2925
1444
     */
1445
    public function testAlterTableChangePrimaryKey() : void
1446
    {
1447
        $tableFrom = new Table('primary_key_id');
1448
        $column    = $tableFrom->addColumn('user_id', 'integer');
1449
        $column->setAutoincrement(true);
1450
        $tableFrom->setPrimaryKey(['user_id']);
1451
        $this->_sm->dropAndCreateTable($tableFrom);
1452
1453
        $tableFrom = $this->_sm->listTableDetails('primary_key_id');
1454
        self::assertEquals(['USER_ID'], \array_map('strtoupper', $tableFrom->getPrimaryKey()->getColumns()));
1455
1456
        $tableTo = new Table('primary_key_id');
1457
        $column  = $tableTo->addColumn('id', 'integer');
1458
        $column->setAutoincrement(true);
1459
        $tableTo->setPrimaryKey(['id']);
1460
1461
        $c    = new Comparator();
1462
        $diff = $c->diffTable($tableFrom, $tableTo);
1463
        $this->_sm->alterTable($diff);
1464
        $tableFinal = $this->_sm->listTableDetails('primary_key_id');
1465
        self::assertEquals(['ID'], \array_map('strtoupper', $tableFinal->getPrimaryKey()->getColumns()));
1466
    }
1467
}
1468