Failed Conditions
Pull Request — master (#2929)
by Alexander
63:56
created

testAlterTableChangePrimaryKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.2
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\Events;
7
use Doctrine\DBAL\Platforms\OraclePlatform;
8
use Doctrine\DBAL\Schema\Column;
9
use Doctrine\DBAL\Schema\ColumnDiff;
10
use Doctrine\DBAL\Schema\Comparator;
11
use Doctrine\DBAL\Schema\Sequence;
12
use Doctrine\DBAL\Schema\Table;
13
use Doctrine\DBAL\Schema\TableDiff;
14
use Doctrine\DBAL\Types\Type;
15
16
class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTestCase
17
{
18
    /**
19
     * @var \Doctrine\DBAL\Schema\AbstractSchemaManager
20
     */
21
    protected $_sm;
22
23
    protected function getPlatformName()
24
    {
25
        $class = get_class($this);
26
        $e = explode('\\', $class);
27
        $testClass = end($e);
28
        $dbms = strtolower(str_replace('SchemaManagerTest', null, $testClass));
29
        return $dbms;
30
    }
31
32
    protected function setUp()
33
    {
34
        parent::setUp();
35
36
        $dbms = $this->getPlatformName();
37
38
        if ($this->_conn->getDatabasePlatform()->getName() !== $dbms) {
39
            $this->markTestSkipped(get_class($this) . ' requires the use of ' . $dbms);
40
        }
41
42
        $this->_sm = $this->_conn->getSchemaManager();
43
    }
44
45
    /**
46
     * @group DBAL-1220
47
     */
48
    public function testDropsDatabaseWithActiveConnections()
49
    {
50
        if (! $this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) {
51
            $this->markTestSkipped('Cannot drop Database client side with this Driver.');
52
        }
53
54
        $this->_sm->dropAndCreateDatabase('test_drop_database');
55
56
        $knownDatabases = $this->_sm->listDatabases();
57
        if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) {
58
            self::assertContains('TEST_DROP_DATABASE', $knownDatabases);
59
        } else {
60
            self::assertContains('test_drop_database', $knownDatabases);
61
        }
62
63
        $params = $this->_conn->getParams();
64
        if ($this->_conn->getDatabasePlatform() instanceof OraclePlatform) {
65
            $params['user'] = 'test_drop_database';
66
        } else {
67
            $params['dbname'] = 'test_drop_database';
68
        }
69
70
        $user = $params['user'] ?? null;
71
        $password = $params['password'] ?? null;
72
73
        $connection = $this->_conn->getDriver()->connect($params, $user, $password);
74
75
        self::assertInstanceOf('Doctrine\DBAL\Driver\Connection', $connection);
76
77
        $this->_sm->dropDatabase('test_drop_database');
78
79
        self::assertNotContains('test_drop_database', $this->_sm->listDatabases());
80
    }
81
82
    /**
83
     * @group DBAL-195
84
     */
85
    public function testDropAndCreateSequence()
86
    {
87
        if ( ! $this->_conn->getDatabasePlatform()->supportsSequences()) {
88
            $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.');
89
        }
90
91
        $name = 'dropcreate_sequences_test_seq';
92
93
        $this->_sm->dropAndCreateSequence(new \Doctrine\DBAL\Schema\Sequence($name, 20, 10));
94
95
        self::assertTrue($this->hasElementWithName($this->_sm->listSequences(), $name));
96
    }
97
98
    private function hasElementWithName(array $items, string $name) : bool
99
    {
100
        $filteredList = array_filter(
101
            $items,
102
            function (\Doctrine\DBAL\Schema\AbstractAsset $item) use ($name) : bool {
103
                return $item->getShortestName($item->getNamespaceName()) === $name;
104
            }
105
        );
106
107
        return count($filteredList) === 1;
108
    }
109
110
    public function testListSequences()
111
    {
112
        if(!$this->_conn->getDatabasePlatform()->supportsSequences()) {
113
            $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.');
114
        }
115
116
        $sequence = new \Doctrine\DBAL\Schema\Sequence('list_sequences_test_seq', 20, 10);
117
        $this->_sm->createSequence($sequence);
118
119
        $sequences = $this->_sm->listSequences();
120
121
        self::assertInternalType('array', $sequences, 'listSequences() should return an array.');
122
123
        $foundSequence = null;
124
        foreach($sequences as $sequence) {
125
            self::assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $sequence, 'Array elements of listSequences() should be Sequence instances.');
126
            if(strtolower($sequence->getName()) == 'list_sequences_test_seq') {
127
                $foundSequence = $sequence;
128
            }
129
        }
130
131
        self::assertNotNull($foundSequence, "Sequence with name 'list_sequences_test_seq' was not found.");
132
        self::assertEquals(20, $foundSequence->getAllocationSize(), "Allocation Size is expected to be 20.");
133
        self::assertEquals(10, $foundSequence->getInitialValue(), "Initial Value is expected to be 10.");
134
    }
135
136
    public function testListDatabases()
137
    {
138
        if (!$this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) {
139
            $this->markTestSkipped('Cannot drop Database client side with this Driver.');
140
        }
141
142
        $this->_sm->dropAndCreateDatabase('test_create_database');
143
        $databases = $this->_sm->listDatabases();
144
145
        $databases = array_map('strtolower', $databases);
146
147
        self::assertContains('test_create_database', $databases);
148
    }
149
150
    /**
151
     * @group DBAL-1058
152
     */
153
    public function testListNamespaceNames()
154
    {
155
        if (!$this->_sm->getDatabasePlatform()->supportsSchemas()) {
156
            $this->markTestSkipped('Platform does not support schemas.');
157
        }
158
159
        // Currently dropping schemas is not supported, so we have to workaround here.
160
        $namespaces = $this->_sm->listNamespaceNames();
161
        $namespaces = array_map('strtolower', $namespaces);
162
163
        if (!in_array('test_create_schema', $namespaces)) {
164
            $this->_conn->executeUpdate($this->_sm->getDatabasePlatform()->getCreateSchemaSQL('test_create_schema'));
165
166
            $namespaces = $this->_sm->listNamespaceNames();
167
            $namespaces = array_map('strtolower', $namespaces);
168
        }
169
170
        self::assertContains('test_create_schema', $namespaces);
171
    }
172
173
    public function testListTables()
174
    {
175
        $this->createTestTable('list_tables_test');
176
        $tables = $this->_sm->listTables();
177
178
        self::assertInternalType('array', $tables);
179
        self::assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'.");
180
181
        $foundTable = false;
182
        foreach ($tables as $table) {
183
            self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table);
184
            if (strtolower($table->getName()) == 'list_tables_test') {
185
                $foundTable = true;
186
187
                self::assertTrue($table->hasColumn('id'));
188
                self::assertTrue($table->hasColumn('test'));
189
                self::assertTrue($table->hasColumn('foreign_key_test'));
190
            }
191
        }
192
193
        self::assertTrue( $foundTable , "The 'list_tables_test' table has to be found.");
194
    }
195
196
    public function createListTableColumns()
197
    {
198
        $table = new Table('list_table_columns');
199
        $table->addColumn('id', 'integer', array('notnull' => true));
200
        $table->addColumn('test', 'string', array('length' => 255, 'notnull' => false, 'default' => 'expected default'));
201
        $table->addColumn('foo', 'text', array('notnull' => true));
202
        $table->addColumn('bar', 'decimal', array('precision' => 10, 'scale' => 4, 'notnull' => false));
203
        $table->addColumn('baz1', 'datetime');
204
        $table->addColumn('baz2', 'time');
205
        $table->addColumn('baz3', 'date');
206
        $table->setPrimaryKey(array('id'));
207
208
        return $table;
209
    }
210
211
    public function testListTableColumns()
212
    {
213
        $table = $this->createListTableColumns();
214
215
        $this->_sm->dropAndCreateTable($table);
216
217
        $columns = $this->_sm->listTableColumns('list_table_columns');
218
        $columnsKeys = array_keys($columns);
219
220
        self::assertArrayHasKey('id', $columns);
221
        self::assertEquals(0, array_search('id', $columnsKeys));
222
        self::assertEquals('id',   strtolower($columns['id']->getname()));
223
        self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['id']->gettype());
224
        self::assertEquals(false,  $columns['id']->getunsigned());
225
        self::assertEquals(true,   $columns['id']->getnotnull());
226
        self::assertEquals(null,   $columns['id']->getdefault());
227
        self::assertInternalType('array',  $columns['id']->getPlatformOptions());
228
229
        self::assertArrayHasKey('test', $columns);
230
        self::assertEquals(1, array_search('test', $columnsKeys));
231
        self::assertEquals('test', strtolower($columns['test']->getname()));
232
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['test']->gettype());
233
        self::assertEquals(255,    $columns['test']->getlength());
234
        self::assertEquals(false,  $columns['test']->getfixed());
235
        self::assertEquals(false,  $columns['test']->getnotnull());
236
        self::assertEquals('expected default',   $columns['test']->getdefault());
237
        self::assertInternalType('array',  $columns['test']->getPlatformOptions());
238
239
        self::assertEquals('foo',  strtolower($columns['foo']->getname()));
240
        self::assertEquals(2, array_search('foo', $columnsKeys));
241
        self::assertInstanceOf('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype());
242
        self::assertEquals(false,  $columns['foo']->getunsigned());
243
        self::assertEquals(false,  $columns['foo']->getfixed());
244
        self::assertEquals(true,   $columns['foo']->getnotnull());
245
        self::assertEquals(null,   $columns['foo']->getdefault());
246
        self::assertInternalType('array',  $columns['foo']->getPlatformOptions());
247
248
        self::assertEquals('bar',  strtolower($columns['bar']->getname()));
249
        self::assertEquals(3, array_search('bar', $columnsKeys));
250
        self::assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $columns['bar']->gettype());
251
        self::assertEquals(null,   $columns['bar']->getlength());
252
        self::assertEquals(10,     $columns['bar']->getprecision());
253
        self::assertEquals(4,      $columns['bar']->getscale());
254
        self::assertEquals(false,  $columns['bar']->getunsigned());
255
        self::assertEquals(false,  $columns['bar']->getfixed());
256
        self::assertEquals(false,  $columns['bar']->getnotnull());
257
        self::assertEquals(null,   $columns['bar']->getdefault());
258
        self::assertInternalType('array',  $columns['bar']->getPlatformOptions());
259
260
        self::assertEquals('baz1', strtolower($columns['baz1']->getname()));
261
        self::assertEquals(4, array_search('baz1', $columnsKeys));
262
        self::assertInstanceOf('Doctrine\DBAL\Types\DateTimeType', $columns['baz1']->gettype());
263
        self::assertEquals(true,   $columns['baz1']->getnotnull());
264
        self::assertEquals(null,   $columns['baz1']->getdefault());
265
        self::assertInternalType('array',  $columns['baz1']->getPlatformOptions());
266
267
        self::assertEquals('baz2', strtolower($columns['baz2']->getname()));
268
        self::assertEquals(5, array_search('baz2', $columnsKeys));
269
        self::assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime'));
270
        self::assertEquals(true,   $columns['baz2']->getnotnull());
271
        self::assertEquals(null,   $columns['baz2']->getdefault());
272
        self::assertInternalType('array',  $columns['baz2']->getPlatformOptions());
273
274
        self::assertEquals('baz3', strtolower($columns['baz3']->getname()));
275
        self::assertEquals(6, array_search('baz3', $columnsKeys));
276
        self::assertContains($columns['baz3']->gettype()->getName(), array('time', 'date', 'datetime'));
277
        self::assertEquals(true,   $columns['baz3']->getnotnull());
278
        self::assertEquals(null,   $columns['baz3']->getdefault());
279
        self::assertInternalType('array',  $columns['baz3']->getPlatformOptions());
280
    }
281
282
    /**
283
     * @group DBAL-1078
284
     */
285
    public function testListTableColumnsWithFixedStringColumn()
286
    {
287
        $tableName = 'test_list_table_fixed_string';
288
289
        $table = new Table($tableName);
290
        $table->addColumn('column_char', 'string', array('fixed' => true, 'length' => 2));
291
292
        $this->_sm->createTable($table);
293
294
        $columns = $this->_sm->listTableColumns($tableName);
295
296
        self::assertArrayHasKey('column_char', $columns);
297
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['column_char']->getType());
298
        self::assertTrue($columns['column_char']->getFixed());
299
        self::assertSame(2, $columns['column_char']->getLength());
300
    }
301
302
    public function testListTableColumnsDispatchEvent()
303
    {
304
        $table = $this->createListTableColumns();
305
306
        $this->_sm->dropAndCreateTable($table);
307
308
        $listenerMock = $this
309
            ->getMockBuilder('ListTableColumnsDispatchEventListener')
310
            ->setMethods(['onSchemaColumnDefinition'])
311
            ->getMock();
312
        $listenerMock
313
            ->expects($this->exactly(7))
314
            ->method('onSchemaColumnDefinition');
315
316
        $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager();
317
318
        $eventManager = new EventManager();
319
        $eventManager->addEventListener(array(Events::onSchemaColumnDefinition), $listenerMock);
320
321
        $this->_sm->getDatabasePlatform()->setEventManager($eventManager);
322
323
        $this->_sm->listTableColumns('list_table_columns');
324
325
        $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager);
326
    }
327
328
    public function testListTableIndexesDispatchEvent()
329
    {
330
        $table = $this->getTestTable('list_table_indexes_test');
331
        $table->addUniqueIndex(array('test'), 'test_index_name');
332
        $table->addIndex(array('id', 'test'), 'test_composite_idx');
333
334
        $this->_sm->dropAndCreateTable($table);
335
336
        $listenerMock = $this
337
            ->getMockBuilder('ListTableIndexesDispatchEventListener')
338
            ->setMethods(['onSchemaIndexDefinition'])
339
            ->getMock();
340
        $listenerMock
341
            ->expects($this->exactly(3))
342
            ->method('onSchemaIndexDefinition');
343
344
        $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager();
345
346
        $eventManager = new EventManager();
347
        $eventManager->addEventListener(array(Events::onSchemaIndexDefinition), $listenerMock);
348
349
        $this->_sm->getDatabasePlatform()->setEventManager($eventManager);
350
351
        $this->_sm->listTableIndexes('list_table_indexes_test');
352
353
        $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager);
354
    }
355
356
    public function testDiffListTableColumns()
357
    {
358
        if ($this->_sm->getDatabasePlatform()->getName() == 'oracle') {
359
            $this->markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).');
360
        }
361
362
        $offlineTable = $this->createListTableColumns();
363
        $this->_sm->dropAndCreateTable($offlineTable);
364
        $onlineTable = $this->_sm->listTableDetails('list_table_columns');
365
366
        $comparator = new \Doctrine\DBAL\Schema\Comparator();
367
        $diff = $comparator->diffTable($offlineTable, $onlineTable);
368
369
        self::assertFalse($diff, "No differences should be detected with the offline vs online schema.");
370
    }
371
372
    public function testListTableIndexes()
373
    {
374
        $table = $this->getTestCompositeTable('list_table_indexes_test');
375
        $table->addUniqueIndex(array('test'), 'test_index_name');
376
        $table->addIndex(array('id', 'test'), 'test_composite_idx');
377
378
        $this->_sm->dropAndCreateTable($table);
379
380
        $tableIndexes = $this->_sm->listTableIndexes('list_table_indexes_test');
381
382
        self::assertEquals(3, count($tableIndexes));
383
384
        self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
385
        self::assertEquals(array('id', 'other_id'), array_map('strtolower', $tableIndexes['primary']->getColumns()));
386
        self::assertTrue($tableIndexes['primary']->isUnique());
387
        self::assertTrue($tableIndexes['primary']->isPrimary());
388
389
        self::assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName()));
390
        self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns()));
391
        self::assertTrue($tableIndexes['test_index_name']->isUnique());
392
        self::assertFalse($tableIndexes['test_index_name']->isPrimary());
393
394
        self::assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName()));
395
        self::assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns()));
396
        self::assertFalse($tableIndexes['test_composite_idx']->isUnique());
397
        self::assertFalse($tableIndexes['test_composite_idx']->isPrimary());
398
    }
399
400
    public function testDropAndCreateIndex()
401
    {
402
        $table = $this->getTestTable('test_create_index');
403
        $table->addUniqueIndex(array('test'), 'test');
404
        $this->_sm->dropAndCreateTable($table);
405
406
        $this->_sm->dropAndCreateIndex($table->getIndex('test'), $table);
407
        $tableIndexes = $this->_sm->listTableIndexes('test_create_index');
408
        self::assertInternalType('array', $tableIndexes);
409
410
        self::assertEquals('test',        strtolower($tableIndexes['test']->getName()));
411
        self::assertEquals(array('test'), array_map('strtolower', $tableIndexes['test']->getColumns()));
412
        self::assertTrue($tableIndexes['test']->isUnique());
413
        self::assertFalse($tableIndexes['test']->isPrimary());
414
    }
415
416
    public function testCreateTableWithForeignKeys()
417
    {
418
        if(!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
419
            $this->markTestSkipped('Platform does not support foreign keys.');
420
        }
421
422
        $tableB = $this->getTestTable('test_foreign');
423
424
        $this->_sm->dropAndCreateTable($tableB);
425
426
        $tableA = $this->getTestTable('test_create_fk');
427
        $tableA->addForeignKeyConstraint('test_foreign', array('foreign_key_test'), array('id'));
428
429
        $this->_sm->dropAndCreateTable($tableA);
430
431
        $fkTable = $this->_sm->listTableDetails('test_create_fk');
432
        $fkConstraints = $fkTable->getForeignKeys();
433
        self::assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key.");
434
435
        $fkConstraint = current($fkConstraints);
436
        self::assertInstanceOf('\Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkConstraint);
437
        self::assertEquals('test_foreign',             strtolower($fkConstraint->getForeignTableName()));
438
        self::assertEquals(array('foreign_key_test'),  array_map('strtolower', $fkConstraint->getColumns()));
439
        self::assertEquals(array('id'),                array_map('strtolower', $fkConstraint->getForeignColumns()));
440
441
        self::assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), "The columns of a foreign key constraint should always be indexed.");
442
    }
443
444
    public function testListForeignKeys()
445
    {
446
        if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
447
            $this->markTestSkipped('Does not support foreign key constraints.');
448
        }
449
450
        $this->createTestTable('test_create_fk1');
451
        $this->createTestTable('test_create_fk2');
452
453
        $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
454
            array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onDelete' => 'CASCADE')
455
        );
456
457
        $this->_sm->createForeignKey($foreignKey, 'test_create_fk1');
458
459
        $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1');
460
461
        self::assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key.");
462
463
        self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
464
        self::assertEquals(array('foreign_key_test'),  array_map('strtolower', $fkeys[0]->getLocalColumns()));
465
        self::assertEquals(array('id'),                array_map('strtolower', $fkeys[0]->getForeignColumns()));
466
        self::assertEquals('test_create_fk2',          strtolower($fkeys[0]->getForeignTableName()));
467
468
        if($fkeys[0]->hasOption('onDelete')) {
469
            self::assertEquals('CASCADE', $fkeys[0]->getOption('onDelete'));
470
        }
471
    }
472
473
    protected function getCreateExampleViewSql()
474
    {
475
        $this->markTestSkipped('No Create Example View SQL was defined for this SchemaManager');
476
    }
477
478
    public function testCreateSchema()
479
    {
480
        $this->createTestTable('test_table');
481
482
        $schema = $this->_sm->createSchema();
483
        self::assertTrue($schema->hasTable('test_table'));
484
    }
485
486
    public function testAlterTableScenario()
487
    {
488
        if(!$this->_sm->getDatabasePlatform()->supportsAlterTable()) {
489
            $this->markTestSkipped('Alter Table is not supported by this platform.');
490
        }
491
492
        $alterTable = $this->createTestTable('alter_table');
493
        $this->createTestTable('alter_table_foreign');
494
495
        $table = $this->_sm->listTableDetails('alter_table');
496
        self::assertTrue($table->hasColumn('id'));
497
        self::assertTrue($table->hasColumn('test'));
498
        self::assertTrue($table->hasColumn('foreign_key_test'));
499
        self::assertEquals(0, count($table->getForeignKeys()));
500
        self::assertEquals(1, count($table->getIndexes()));
501
502
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
503
        $tableDiff->fromTable = $alterTable;
504
        $tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer'));
505
        $tableDiff->removedColumns['test'] = $table->getColumn('test');
506
507
        $this->_sm->alterTable($tableDiff);
508
509
        $table = $this->_sm->listTableDetails('alter_table');
510
        self::assertFalse($table->hasColumn('test'));
511
        self::assertTrue($table->hasColumn('foo'));
512
513
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
514
        $tableDiff->fromTable = $table;
515
        $tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo'));
516
517
        $this->_sm->alterTable($tableDiff);
518
519
        $table = $this->_sm->listTableDetails('alter_table');
520
        self::assertEquals(2, count($table->getIndexes()));
521
        self::assertTrue($table->hasIndex('foo_idx'));
522
        self::assertEquals(array('foo'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
523
        self::assertFalse($table->getIndex('foo_idx')->isPrimary());
524
        self::assertFalse($table->getIndex('foo_idx')->isUnique());
525
526
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
527
        $tableDiff->fromTable = $table;
528
        $tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test'));
529
530
        $this->_sm->alterTable($tableDiff);
531
532
        $table = $this->_sm->listTableDetails('alter_table');
533
        self::assertEquals(2, count($table->getIndexes()));
534
        self::assertTrue($table->hasIndex('foo_idx'));
535
        self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns()));
536
537
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
538
        $tableDiff->fromTable = $table;
539
        $tableDiff->renamedIndexes['foo_idx'] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
540
541
        $this->_sm->alterTable($tableDiff);
542
543
        $table = $this->_sm->listTableDetails('alter_table');
544
        self::assertEquals(2, count($table->getIndexes()));
545
        self::assertTrue($table->hasIndex('bar_idx'));
546
        self::assertFalse($table->hasIndex('foo_idx'));
547
        self::assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('bar_idx')->getColumns()));
548
        self::assertFalse($table->getIndex('bar_idx')->isPrimary());
549
        self::assertFalse($table->getIndex('bar_idx')->isUnique());
550
551
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table");
552
        $tableDiff->fromTable = $table;
553
        $tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('bar_idx', array('foo', 'foreign_key_test'));
554
        $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id'));
555
        $tableDiff->addedForeignKeys[] = $fk;
556
557
        $this->_sm->alterTable($tableDiff);
558
        $table = $this->_sm->listTableDetails('alter_table');
559
560
        // dont check for index size here, some platforms automatically add indexes for foreign keys.
561
        self::assertFalse($table->hasIndex('bar_idx'));
562
563
        if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
564
            $fks = $table->getForeignKeys();
565
            self::assertCount(1, $fks);
566
            $foreignKey = current($fks);
567
            self::assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName()));
568
            self::assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns()));
569
            self::assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns()));
570
        }
571
    }
572
573
    public function testCreateAndListViews()
574
    {
575
        if (!$this->_sm->getDatabasePlatform()->supportsViews()) {
576
            $this->markTestSkipped('Views is not supported by this platform.');
577
        }
578
579
        $this->createTestTable('view_test_table');
580
581
        $name = "doctrine_test_view";
582
        $sql = "SELECT * FROM view_test_table";
583
584
        $view = new \Doctrine\DBAL\Schema\View($name, $sql);
585
586
        $this->_sm->dropAndCreateView($view);
587
588
        self::assertTrue($this->hasElementWithName($this->_sm->listViews(), $name));
589
    }
590
591
    public function testAutoincrementDetection()
592
    {
593
        if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) {
594
            $this->markTestSkipped('This test is only supported on platforms that have autoincrement');
595
        }
596
597
        $table = new Table('test_autoincrement');
598
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
599
        $table->addColumn('id', 'integer', array('autoincrement' => true));
600
        $table->setPrimaryKey(array('id'));
601
602
        $this->_sm->createTable($table);
603
604
        $inferredTable = $this->_sm->listTableDetails('test_autoincrement');
605
        self::assertTrue($inferredTable->hasColumn('id'));
606
        self::assertTrue($inferredTable->getColumn('id')->getAutoincrement());
607
    }
608
609
    /**
610
     * @group DBAL-792
611
     */
612
    public function testAutoincrementDetectionMulticolumns()
613
    {
614
        if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) {
615
            $this->markTestSkipped('This test is only supported on platforms that have autoincrement');
616
        }
617
618
        $table = new Table('test_not_autoincrement');
619
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
620
        $table->addColumn('id', 'integer');
621
        $table->addColumn('other_id', 'integer');
622
        $table->setPrimaryKey(array('id', 'other_id'));
623
624
        $this->_sm->createTable($table);
625
626
        $inferredTable = $this->_sm->listTableDetails('test_not_autoincrement');
627
        self::assertTrue($inferredTable->hasColumn('id'));
628
        self::assertFalse($inferredTable->getColumn('id')->getAutoincrement());
629
    }
630
631
    /**
632
     * @group DDC-887
633
     */
634
    public function testUpdateSchemaWithForeignKeyRenaming()
635
    {
636
        if (!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
637
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
638
        }
639
640
        $table = new Table('test_fk_base');
641
        $table->addColumn('id', 'integer');
642
        $table->setPrimaryKey(array('id'));
643
644
        $tableFK = new Table('test_fk_rename');
645
        $tableFK->setSchemaConfig($this->_sm->createSchemaConfig());
646
        $tableFK->addColumn('id', 'integer');
647
        $tableFK->addColumn('fk_id', 'integer');
648
        $tableFK->setPrimaryKey(array('id'));
649
        $tableFK->addIndex(array('fk_id'), 'fk_idx');
650
        $tableFK->addForeignKeyConstraint('test_fk_base', array('fk_id'), array('id'));
651
652
        $this->_sm->createTable($table);
653
        $this->_sm->createTable($tableFK);
654
655
        $tableFKNew = new Table('test_fk_rename');
656
        $tableFKNew->setSchemaConfig($this->_sm->createSchemaConfig());
657
        $tableFKNew->addColumn('id', 'integer');
658
        $tableFKNew->addColumn('rename_fk_id', 'integer');
659
        $tableFKNew->setPrimaryKey(array('id'));
660
        $tableFKNew->addIndex(array('rename_fk_id'), 'fk_idx');
661
        $tableFKNew->addForeignKeyConstraint('test_fk_base', array('rename_fk_id'), array('id'));
662
663
        $c = new \Doctrine\DBAL\Schema\Comparator();
664
        $tableDiff = $c->diffTable($tableFK, $tableFKNew);
665
666
        $this->_sm->alterTable($tableDiff);
667
668
        $table       = $this->_sm->listTableDetails('test_fk_rename');
669
        $foreignKeys = $table->getForeignKeys();
670
671
        self::assertTrue($table->hasColumn('rename_fk_id'));
672
        self::assertCount(1, $foreignKeys);
673
        self::assertSame(['rename_fk_id'], array_map('strtolower', current($foreignKeys)->getColumns()));
674
    }
675
676
    /**
677
     * @group DBAL-1062
678
     */
679
    public function testRenameIndexUsedInForeignKeyConstraint()
680
    {
681
        if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
682
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
683
        }
684
685
        $primaryTable = new Table('test_rename_index_primary');
686
        $primaryTable->addColumn('id', 'integer');
687
        $primaryTable->setPrimaryKey(array('id'));
688
689
        $foreignTable = new Table('test_rename_index_foreign');
690
        $foreignTable->addColumn('fk', 'integer');
691
        $foreignTable->addIndex(array('fk'), 'rename_index_fk_idx');
692
        $foreignTable->addForeignKeyConstraint(
693
            'test_rename_index_primary',
694
            array('fk'),
695
            array('id'),
696
            array(),
697
            'fk_constraint'
698
        );
699
700
        $this->_sm->dropAndCreateTable($primaryTable);
701
        $this->_sm->dropAndCreateTable($foreignTable);
702
703
        $foreignTable2 = clone $foreignTable;
704
        $foreignTable2->renameIndex('rename_index_fk_idx', 'renamed_index_fk_idx');
705
706
        $comparator = new Comparator();
707
708
        $this->_sm->alterTable($comparator->diffTable($foreignTable, $foreignTable2));
709
710
        $foreignTable = $this->_sm->listTableDetails('test_rename_index_foreign');
711
712
        self::assertFalse($foreignTable->hasIndex('rename_index_fk_idx'));
713
        self::assertTrue($foreignTable->hasIndex('renamed_index_fk_idx'));
714
        self::assertTrue($foreignTable->hasForeignKey('fk_constraint'));
715
    }
716
717
    /**
718
     * @group DBAL-42
719
     */
720
    public function testGetColumnComment()
721
    {
722
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
723
             ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
724
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
725
            $this->markTestSkipped('Database does not support column comments.');
726
        }
727
728
        $table = new Table('column_comment_test');
729
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
730
        $table->setPrimaryKey(array('id'));
731
732
        $this->_sm->createTable($table);
733
734
        $columns = $this->_sm->listTableColumns("column_comment_test");
735
        self::assertEquals(1, count($columns));
736
        self::assertEquals('This is a comment', $columns['id']->getComment());
737
738
        $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('column_comment_test');
739
        $tableDiff->fromTable = $table;
740
        $tableDiff->changedColumns['id'] = new \Doctrine\DBAL\Schema\ColumnDiff(
741
            'id', new \Doctrine\DBAL\Schema\Column(
742
                'id', \Doctrine\DBAL\Types\Type::getType('integer')
743
            ),
744
            array('comment'),
745
            new \Doctrine\DBAL\Schema\Column(
746
                'id', \Doctrine\DBAL\Types\Type::getType('integer'), array('comment' => 'This is a comment')
747
            )
748
        );
749
750
        $this->_sm->alterTable($tableDiff);
751
752
        $columns = $this->_sm->listTableColumns("column_comment_test");
753
        self::assertEquals(1, count($columns));
754
        self::assertEmpty($columns['id']->getComment());
755
    }
756
757
    /**
758
     * @group DBAL-42
759
     */
760
    public function testAutomaticallyAppendCommentOnMarkedColumns()
761
    {
762
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
763
             ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
764
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
765
            $this->markTestSkipped('Database does not support column comments.');
766
        }
767
768
        $table = new Table('column_comment_test2');
769
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
770
        $table->addColumn('obj', 'object', array('comment' => 'This is a comment'));
771
        $table->addColumn('arr', 'array', array('comment' => 'This is a comment'));
772
        $table->setPrimaryKey(array('id'));
773
774
        $this->_sm->createTable($table);
775
776
        $columns = $this->_sm->listTableColumns("column_comment_test2");
777
        self::assertEquals(3, count($columns));
778
        self::assertEquals('This is a comment', $columns['id']->getComment());
779
        self::assertEquals('This is a comment', $columns['obj']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
780
        self::assertInstanceOf('Doctrine\DBAL\Types\ObjectType', $columns['obj']->getType(), "The Doctrine2 should be detected from comment hint.");
781
        self::assertEquals('This is a comment', $columns['arr']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
782
        self::assertInstanceOf('Doctrine\DBAL\Types\ArrayType', $columns['arr']->getType(), "The Doctrine2 should be detected from comment hint.");
783
    }
784
785
    /**
786
     * @group DBAL-1228
787
     */
788
    public function testCommentHintOnDateIntervalTypeColumn()
789
    {
790
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
791
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
792
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
793
            $this->markTestSkipped('Database does not support column comments.');
794
        }
795
796
        $table = new Table('column_dateinterval_comment');
797
        $table->addColumn('id', 'integer', array('comment' => 'This is a comment'));
798
        $table->addColumn('date_interval', 'dateinterval', array('comment' => 'This is a comment'));
799
        $table->setPrimaryKey(array('id'));
800
801
        $this->_sm->createTable($table);
802
803
        $columns = $this->_sm->listTableColumns("column_dateinterval_comment");
804
        self::assertEquals(2, count($columns));
805
        self::assertEquals('This is a comment', $columns['id']->getComment());
806
        self::assertEquals('This is a comment', $columns['date_interval']->getComment(), "The Doctrine2 Typehint should be stripped from comment.");
807
        self::assertInstanceOf('Doctrine\DBAL\Types\DateIntervalType', $columns['date_interval']->getType(), "The Doctrine2 should be detected from comment hint.");
808
    }
809
810
    /**
811
     * @group DBAL-825
812
     */
813
    public function testChangeColumnsTypeWithDefaultValue()
814
    {
815
        $tableName = 'column_def_change_type';
816
        $table     = new Table($tableName);
817
818
        $table->addColumn('col_int', 'smallint', array('default' => 666));
819
        $table->addColumn('col_string', 'string', array('default' => 'foo'));
820
821
        $this->_sm->dropAndCreateTable($table);
822
823
        $tableDiff = new TableDiff($tableName);
824
        $tableDiff->fromTable = $table;
825
        $tableDiff->changedColumns['col_int'] = new ColumnDiff(
826
            'col_int',
827
            new Column('col_int', Type::getType('integer'), array('default' => 666)),
828
            array('type'),
829
            new Column('col_int', Type::getType('smallint'), array('default' => 666))
830
        );
831
832
        $tableDiff->changedColumns['col_string'] = new ColumnDiff(
833
            'col_string',
834
            new Column('col_string', Type::getType('string'), array('default' => 'foo', 'fixed' => true)),
835
            array('fixed'),
836
            new Column('col_string', Type::getType('string'), array('default' => 'foo'))
837
        );
838
839
        $this->_sm->alterTable($tableDiff);
840
841
        $columns = $this->_sm->listTableColumns($tableName);
842
843
        self::assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['col_int']->getType());
844
        self::assertEquals(666, $columns['col_int']->getDefault());
845
846
        self::assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['col_string']->getType());
847
        self::assertEquals('foo', $columns['col_string']->getDefault());
848
    }
849
850
    /**
851
     * @group DBAL-197
852
     */
853
    public function testListTableWithBlob()
854
    {
855
        $table = new Table('test_blob_table');
856
        $table->addColumn('id', 'integer', ['comment' => 'This is a comment']);
857
        $table->addColumn('binarydata', 'blob', []);
858
        $table->setPrimaryKey(['id']);
859
860
        $this->_sm->createTable($table);
861
862
        $created = $this->_sm->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 string $name
871
     * @param array  $data
872
     * @return Table
873
     */
874
    protected function createTestTable($name = 'test_table', $data = array())
875
    {
876
        $options = $data['options'] ?? [];
877
878
        $table = $this->getTestTable($name, $options);
879
880
        $this->_sm->dropAndCreateTable($table);
881
882
        return $table;
883
    }
884
885
    protected function getTestTable($name, $options=array())
886
    {
887
        $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

887
        $table = new Table($name, array(), array(), array(), /** @scrutinizer ignore-type */ false, $options);
Loading history...
888
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
889
        $table->addColumn('id', 'integer', array('notnull' => true));
890
        $table->setPrimaryKey(array('id'));
891
        $table->addColumn('test', 'string', array('length' => 255));
892
        $table->addColumn('foreign_key_test', 'integer');
893
        return $table;
894
    }
895
896
    protected function getTestCompositeTable($name)
897
    {
898
        $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

898
        $table = new Table($name, array(), array(), array(), /** @scrutinizer ignore-type */ false, array());
Loading history...
899
        $table->setSchemaConfig($this->_sm->createSchemaConfig());
900
        $table->addColumn('id', 'integer', array('notnull' => true));
901
        $table->addColumn('other_id', 'integer', array('notnull' => true));
902
        $table->setPrimaryKey(array('id', 'other_id'));
903
        $table->addColumn('test', 'string', array('length' => 255));
904
        return $table;
905
    }
906
907
    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

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