Failed Conditions
Pull Request — master (#2850)
by Adrien
33:12 queued 23:11
created

createTableForDefaultValues()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
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.");
0 ignored issues
show
Bug introduced by
The method getAllocationSize() does not exist on null. ( Ignorable by Annotation )

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

132
        self::assertEquals(20, $foundSequence->/** @scrutinizer ignore-call */ getAllocationSize(), "Allocation Size is expected to be 20.");

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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.");
0 ignored issues
show
Bug introduced by
$diff of type Doctrine\DBAL\Schema\TableDiff is incompatible with the type boolean expected by parameter $condition of PHPUnit\Framework\Assert::assertFalse(). ( Ignorable by Annotation )

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

369
        self::assertFalse(/** @scrutinizer ignore-type */ $diff, "No differences should be detected with the offline vs online schema.");
Loading history...
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 = array();
877
        if (isset($data['options'])) {
878
            $options = $data['options'];
879
        }
880
881
        $table = $this->getTestTable($name, $options);
882
883
        $this->_sm->dropAndCreateTable($table);
884
885
        return $table;
886
    }
887
888
    protected function getTestTable($name, $options=array())
889
    {
890
        $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

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

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

910
    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...
911
    {
912
        $foundTable = false;
913
        foreach ($tables as $table) {
914
            self::assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.');
915
            if (strtolower($table->getName()) == 'list_tables_test_new_name') {
916
                $foundTable = true;
917
            }
918
        }
919
        self::assertTrue($foundTable, "Could not find new table");
920
    }
921
922
    public function testListForeignKeysComposite()
923
    {
924
        if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
925
            $this->markTestSkipped('Does not support foreign key constraints.');
926
        }
927
928
        $this->_sm->createTable($this->getTestTable('test_create_fk3'));
929
        $this->_sm->createTable($this->getTestCompositeTable('test_create_fk4'));
930
931
        $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
932
            array('id', 'foreign_key_test'), 'test_create_fk4', array('id', 'other_id'), 'foreign_key_test_fk2'
933
        );
934
935
        $this->_sm->createForeignKey($foreignKey, 'test_create_fk3');
936
937
        $fkeys = $this->_sm->listTableForeignKeys('test_create_fk3');
938
939
        self::assertEquals(1, count($fkeys), "Table 'test_create_fk3' has to have one foreign key.");
940
941
        self::assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
942
        self::assertEquals(array('id', 'foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns()));
943
        self::assertEquals(array('id', 'other_id'),         array_map('strtolower', $fkeys[0]->getForeignColumns()));
944
    }
945
946
    /**
947
     * @group DBAL-44
948
     */
949
    public function testColumnDefaultLifecycle()
950
    {
951
        $table = new Table("col_def_lifecycle");
952
        $table->addColumn('id', 'integer', array('autoincrement' => true));
953
        $table->addColumn('column1', 'string', array('default' => null));
954
        $table->addColumn('column2', 'string', array('default' => false));
955
        $table->addColumn('column3', 'string', array('default' => true));
956
        $table->addColumn('column4', 'string', array('default' => 0));
957
        $table->addColumn('column5', 'string', array('default' => ''));
958
        $table->addColumn('column6', 'string', array('default' => 'def'));
959
        $table->addColumn('column7', 'integer', array('default' => 0));
960
        $table->setPrimaryKey(array('id'));
961
962
        $this->_sm->dropAndCreateTable($table);
963
964
        $columns = $this->_sm->listTableColumns('col_def_lifecycle');
965
966
        self::assertNull($columns['id']->getDefault());
967
        self::assertNull($columns['column1']->getDefault());
968
        self::assertSame('', $columns['column2']->getDefault());
969
        self::assertSame('1', $columns['column3']->getDefault());
970
        self::assertSame('0', $columns['column4']->getDefault());
971
        self::assertSame('', $columns['column5']->getDefault());
972
        self::assertSame('def', $columns['column6']->getDefault());
973
        self::assertSame('0', $columns['column7']->getDefault());
974
975
        $diffTable = clone $table;
976
977
        $diffTable->changeColumn('column1', array('default' => false));
978
        $diffTable->changeColumn('column2', array('default' => null));
979
        $diffTable->changeColumn('column3', array('default' => false));
980
        $diffTable->changeColumn('column4', array('default' => null));
981
        $diffTable->changeColumn('column5', array('default' => false));
982
        $diffTable->changeColumn('column6', array('default' => 666));
983
        $diffTable->changeColumn('column7', array('default' => null));
984
985
        $comparator = new Comparator();
986
987
        $this->_sm->alterTable($comparator->diffTable($table, $diffTable));
988
989
        $columns = $this->_sm->listTableColumns('col_def_lifecycle');
990
991
        self::assertSame('', $columns['column1']->getDefault());
992
        self::assertNull($columns['column2']->getDefault());
993
        self::assertSame('', $columns['column3']->getDefault());
994
        self::assertNull($columns['column4']->getDefault());
995
        self::assertSame('', $columns['column5']->getDefault());
996
        self::assertSame('666', $columns['column6']->getDefault());
997
        self::assertNull($columns['column7']->getDefault());
998
    }
999
1000
    public function testListTableWithBinary()
1001
    {
1002
        $tableName = 'test_binary_table';
1003
1004
        $table = new Table($tableName);
1005
        $table->addColumn('id', 'integer');
1006
        $table->addColumn('column_varbinary', 'binary', array());
1007
        $table->addColumn('column_binary', 'binary', array('fixed' => true));
1008
        $table->setPrimaryKey(array('id'));
1009
1010
        $this->_sm->createTable($table);
1011
1012
        $table = $this->_sm->listTableDetails($tableName);
1013
1014
        self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_varbinary')->getType());
1015
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
1016
1017
        self::assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_binary')->getType());
1018
        self::assertTrue($table->getColumn('column_binary')->getFixed());
1019
    }
1020
1021
    public function testListTableDetailsWithFullQualifiedTableName()
1022
    {
1023
        if ( ! $this->_sm->getDatabasePlatform()->supportsSchemas()) {
1024
            $this->markTestSkipped('Test only works on platforms that support schemas.');
1025
        }
1026
1027
        $defaultSchemaName = $this->_sm->getDatabasePlatform()->getDefaultSchemaName();
1028
        $primaryTableName  = 'primary_table';
1029
        $foreignTableName  = 'foreign_table';
1030
1031
        $table = new Table($foreignTableName);
1032
        $table->addColumn('id', 'integer', array('autoincrement' => true));
1033
        $table->setPrimaryKey(array('id'));
1034
1035
        $this->_sm->dropAndCreateTable($table);
1036
1037
        $table = new Table($primaryTableName);
1038
        $table->addColumn('id', 'integer', array('autoincrement' => true));
1039
        $table->addColumn('foo', 'integer');
1040
        $table->addColumn('bar', 'string');
1041
        $table->addForeignKeyConstraint($foreignTableName, array('foo'), array('id'));
1042
        $table->addIndex(array('bar'));
1043
        $table->setPrimaryKey(array('id'));
1044
1045
        $this->_sm->dropAndCreateTable($table);
1046
1047
        self::assertEquals(
1048
            $this->_sm->listTableColumns($primaryTableName),
1049
            $this->_sm->listTableColumns($defaultSchemaName . '.' . $primaryTableName)
1050
        );
1051
        self::assertEquals(
1052
            $this->_sm->listTableIndexes($primaryTableName),
1053
            $this->_sm->listTableIndexes($defaultSchemaName . '.' . $primaryTableName)
1054
        );
1055
        self::assertEquals(
1056
            $this->_sm->listTableForeignKeys($primaryTableName),
1057
            $this->_sm->listTableForeignKeys($defaultSchemaName . '.' . $primaryTableName)
1058
        );
1059
    }
1060
1061
    public function testCommentStringsAreQuoted()
1062
    {
1063
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
1064
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
1065
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
1066
            $this->markTestSkipped('Database does not support column comments.');
1067
        }
1068
1069
        $table = new Table('my_table');
1070
        $table->addColumn('id', 'integer', array('comment' => "It's a comment with a quote"));
1071
        $table->setPrimaryKey(array('id'));
1072
1073
        $this->_sm->createTable($table);
1074
1075
        $columns = $this->_sm->listTableColumns("my_table");
1076
        self::assertEquals("It's a comment with a quote", $columns['id']->getComment());
1077
    }
1078
1079
    public function testCommentNotDuplicated()
1080
    {
1081
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments()) {
1082
            $this->markTestSkipped('Database does not support column comments.');
1083
        }
1084
1085
        $options = array(
1086
            'type' => Type::getType('integer'),
1087
            'default' => 0,
1088
            'notnull' => true,
1089
            'comment' => 'expected+column+comment',
1090
        );
1091
        $columnDefinition = substr($this->_conn->getDatabasePlatform()->getColumnDeclarationSQL('id', $options), strlen('id') + 1);
1092
1093
        $table = new Table('my_table');
1094
        $table->addColumn('id', 'integer', array('columnDefinition' => $columnDefinition, 'comment' => 'unexpected_column_comment'));
1095
        $sql = $this->_conn->getDatabasePlatform()->getCreateTableSQL($table);
1096
1097
        self::assertContains('expected+column+comment', $sql[0]);
1098
        self::assertNotContains('unexpected_column_comment', $sql[0]);
1099
    }
1100
1101
    /**
1102
     * @group DBAL-1009
1103
     *
1104
     * @dataProvider getAlterColumnComment
1105
     */
1106
    public function testAlterColumnComment($comment1, $expectedComment1, $comment2, $expectedComment2)
1107
    {
1108
        if ( ! $this->_conn->getDatabasePlatform()->supportsInlineColumnComments() &&
1109
            ! $this->_conn->getDatabasePlatform()->supportsCommentOnStatement() &&
1110
            $this->_conn->getDatabasePlatform()->getName() != 'mssql') {
1111
            $this->markTestSkipped('Database does not support column comments.');
1112
        }
1113
1114
        $offlineTable = new Table('alter_column_comment_test');
1115
        $offlineTable->addColumn('comment1', 'integer', array('comment' => $comment1));
1116
        $offlineTable->addColumn('comment2', 'integer', array('comment' => $comment2));
1117
        $offlineTable->addColumn('no_comment1', 'integer');
1118
        $offlineTable->addColumn('no_comment2', 'integer');
1119
        $this->_sm->dropAndCreateTable($offlineTable);
1120
1121
        $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test");
1122
1123
        self::assertSame($expectedComment1, $onlineTable->getColumn('comment1')->getComment());
1124
        self::assertSame($expectedComment2, $onlineTable->getColumn('comment2')->getComment());
1125
        self::assertNull($onlineTable->getColumn('no_comment1')->getComment());
1126
        self::assertNull($onlineTable->getColumn('no_comment2')->getComment());
1127
1128
        $onlineTable->changeColumn('comment1', array('comment' => $comment2));
1129
        $onlineTable->changeColumn('comment2', array('comment' => $comment1));
1130
        $onlineTable->changeColumn('no_comment1', array('comment' => $comment1));
1131
        $onlineTable->changeColumn('no_comment2', array('comment' => $comment2));
1132
1133
        $comparator = new Comparator();
1134
1135
        $tableDiff = $comparator->diffTable($offlineTable, $onlineTable);
1136
1137
        self::assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
1138
1139
        $this->_sm->alterTable($tableDiff);
1140
1141
        $onlineTable = $this->_sm->listTableDetails("alter_column_comment_test");
1142
1143
        self::assertSame($expectedComment2, $onlineTable->getColumn('comment1')->getComment());
1144
        self::assertSame($expectedComment1, $onlineTable->getColumn('comment2')->getComment());
1145
        self::assertSame($expectedComment1, $onlineTable->getColumn('no_comment1')->getComment());
1146
        self::assertSame($expectedComment2, $onlineTable->getColumn('no_comment2')->getComment());
1147
    }
1148
1149
    public function getAlterColumnComment()
1150
    {
1151
        return array(
1152
            array(null, null, ' ', ' '),
1153
            array(null, null, '0', '0'),
1154
            array(null, null, 'foo', 'foo'),
1155
1156
            array('', null, ' ', ' '),
1157
            array('', null, '0', '0'),
1158
            array('', null, 'foo', 'foo'),
1159
1160
            array(' ', ' ', '0', '0'),
1161
            array(' ', ' ', 'foo', 'foo'),
1162
1163
            array('0', '0', 'foo', 'foo'),
1164
        );
1165
    }
1166
1167
    /**
1168
     * @group DBAL-1095
1169
     */
1170
    public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys()
1171
    {
1172
        if (! $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
1173
            $this->markTestSkipped('This test is only supported on platforms that have foreign keys.');
1174
        }
1175
1176
        $primaryTable = new Table('test_list_index_impl_primary');
1177
        $primaryTable->addColumn('id', 'integer');
1178
        $primaryTable->setPrimaryKey(array('id'));
1179
1180
        $foreignTable = new Table('test_list_index_impl_foreign');
1181
        $foreignTable->addColumn('fk1', 'integer');
1182
        $foreignTable->addColumn('fk2', 'integer');
1183
        $foreignTable->addIndex(array('fk1'), 'explicit_fk1_idx');
1184
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk1'), array('id'));
1185
        $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', array('fk2'), array('id'));
1186
1187
        $this->_sm->dropAndCreateTable($primaryTable);
1188
        $this->_sm->dropAndCreateTable($foreignTable);
1189
1190
        $indexes = $this->_sm->listTableIndexes('test_list_index_impl_foreign');
1191
1192
        self::assertCount(2, $indexes);
1193
        self::assertArrayHasKey('explicit_fk1_idx', $indexes);
1194
        self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes);
1195
    }
1196
1197
    /**
1198
     * @after
1199
     */
1200
    public function removeJsonArrayTable() : void
1201
    {
1202
        if ($this->_sm->tablesExist(['json_array_test'])) {
1203
            $this->_sm->dropTable('json_array_test');
1204
        }
1205
    }
1206
1207
    /**
1208
     * @group 2782
1209
     * @group 6654
1210
     */
1211
    public function testComparatorShouldReturnFalseWhenLegacyJsonArrayColumnHasComment() : void
1212
    {
1213
        $table = new Table('json_array_test');
1214
        $table->addColumn('parameters', 'json_array');
1215
1216
        $this->_sm->createTable($table);
1217
1218
        $comparator = new Comparator();
1219
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1220
1221
        self::assertFalse($tableDiff);
0 ignored issues
show
Bug introduced by
$tableDiff of type Doctrine\DBAL\Schema\TableDiff is incompatible with the type boolean expected by parameter $condition of PHPUnit\Framework\Assert::assertFalse(). ( Ignorable by Annotation )

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

1221
        self::assertFalse(/** @scrutinizer ignore-type */ $tableDiff);
Loading history...
1222
    }
1223
1224
    /**
1225
     * @group 2782
1226
     * @group 6654
1227
     */
1228
    public function testComparatorShouldModifyOnlyTheCommentWhenUpdatingFromJsonArrayTypeOnLegacyPlatforms() : void
1229
    {
1230
        if ($this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1231
            $this->markTestSkipped('This test is only supported on platforms that do not have native JSON type.');
1232
        }
1233
1234
        $table = new Table('json_array_test');
1235
        $table->addColumn('parameters', 'json_array');
1236
1237
        $this->_sm->createTable($table);
1238
1239
        $table = new Table('json_array_test');
1240
        $table->addColumn('parameters', 'json');
1241
1242
        $comparator = new Comparator();
1243
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1244
1245
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1246
1247
        $changedColumn = $tableDiff->changedColumns['parameters'] ?? $tableDiff->changedColumns['PARAMETERS'];
1248
1249
        self::assertSame(['comment'], $changedColumn->changedProperties);
1250
    }
1251
1252
    /**
1253
     * @group 2782
1254
     * @group 6654
1255
     */
1256
    public function testComparatorShouldAddCommentToLegacyJsonArrayTypeThatDoesNotHaveIt() : void
1257
    {
1258
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1259
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1260
        }
1261
1262
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON NOT NULL)');
1263
1264
        $table = new Table('json_array_test');
1265
        $table->addColumn('parameters', 'json_array');
1266
1267
        $comparator = new Comparator();
1268
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1269
1270
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1271
        self::assertSame(['comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1272
    }
1273
1274
    /**
1275
     * @group 2782
1276
     * @group 6654
1277
     */
1278
    public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayType() : void
1279
    {
1280
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1281
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1282
        }
1283
1284
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)');
1285
1286
        $table = new Table('json_array_test');
1287
        $table->addColumn('parameters', 'json_array');
1288
1289
        $comparator = new Comparator();
1290
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1291
1292
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1293
        self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1294
    }
1295
1296
    /**
1297
     * @group 2782
1298
     * @group 6654
1299
     */
1300
    public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayTypeEvenWhenPlatformHasJsonSupport() : void
1301
    {
1302
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1303
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1304
        }
1305
1306
        $this->_conn->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)');
1307
1308
        $table = new Table('json_array_test');
1309
        $table->addColumn('parameters', 'json_array');
1310
1311
        $comparator = new Comparator();
1312
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_array_test'), $table);
1313
1314
        self::assertInstanceOf(TableDiff::class, $tableDiff);
1315
        self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties);
1316
    }
1317
1318
    /**
1319
     * @group 2782
1320
     * @group 6654
1321
     */
1322
    public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNow() : void
1323
    {
1324
        if ( ! $this->_sm->getDatabasePlatform()->hasNativeJsonType()) {
1325
            $this->markTestSkipped('This test is only supported on platforms that have native JSON type.');
1326
        }
1327
1328
        $this->_conn->executeQuery('CREATE TABLE json_test (parameters JSON NOT NULL)');
1329
1330
        $table = new Table('json_test');
1331
        $table->addColumn('parameters', 'json');
1332
1333
        $comparator = new Comparator();
1334
        $tableDiff  = $comparator->diffTable($this->_sm->listTableDetails('json_test'), $table);
1335
1336
        self::assertFalse($tableDiff);
0 ignored issues
show
Bug introduced by
$tableDiff of type Doctrine\DBAL\Schema\TableDiff is incompatible with the type boolean expected by parameter $condition of PHPUnit\Framework\Assert::assertFalse(). ( Ignorable by Annotation )

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

1336
        self::assertFalse(/** @scrutinizer ignore-type */ $tableDiff);
Loading history...
1337
    }
1338
1339
    /**
1340
     * @dataProvider commentsProvider
1341
     *
1342
     * @group 2596
1343
     */
1344
    public function testExtractDoctrineTypeFromComment(string $comment, string $expected, string $currentType) : void
1345
    {
1346
        $result = $this->_sm->extractDoctrineTypeFromComment($comment, $currentType);
1347
1348
        self::assertSame($expected, $result);
1349
    }
1350
1351
    public function commentsProvider() : array
1352
    {
1353
        $currentType = 'current type';
1354
1355
        return [
1356
            'invalid custom type comments'      => ['should.return.current.type', $currentType, $currentType],
1357
            'valid doctrine type'               => ['(DC2Type:guid)', 'guid', $currentType],
1358
            'valid with dots'                   => ['(DC2Type:type.should.return)', 'type.should.return', $currentType],
1359
            'valid with namespace'              => ['(DC2Type:Namespace\Class)', 'Namespace\Class', $currentType],
1360
            'valid with extra closing bracket'  => ['(DC2Type:should.stop)).before)', 'should.stop', $currentType],
1361
            'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop', $currentType],
1362
        ];
1363
    }
1364
1365
    public function testCreateAndListSequences() : void
1366
    {
1367
        if ( ! $this->_sm->getDatabasePlatform()->supportsSequences()) {
1368
            self::markTestSkipped('This test is only supported on platforms that support sequences.');
1369
        }
1370
1371
        $sequence1Name           = 'sequence_1';
1372
        $sequence1AllocationSize = 1;
1373
        $sequence1InitialValue   = 2;
1374
        $sequence2Name           = 'sequence_2';
1375
        $sequence2AllocationSize = 3;
1376
        $sequence2InitialValue   = 4;
1377
        $sequence1               = new Sequence($sequence1Name, $sequence1AllocationSize, $sequence1InitialValue);
1378
        $sequence2               = new Sequence($sequence2Name, $sequence2AllocationSize, $sequence2InitialValue);
1379
1380
        $this->_sm->createSequence($sequence1);
1381
        $this->_sm->createSequence($sequence2);
1382
1383
        /** @var Sequence[] $actualSequences */
1384
        $actualSequences = [];
1385
        foreach ($this->_sm->listSequences() as $sequence) {
1386
            $actualSequences[$sequence->getName()] = $sequence;
1387
        }
1388
1389
        $actualSequence1 = $actualSequences[$sequence1Name];
1390
        $actualSequence2 = $actualSequences[$sequence2Name];
1391
1392
        self::assertSame($sequence1Name, $actualSequence1->getName());
1393
        self::assertEquals($sequence1AllocationSize, $actualSequence1->getAllocationSize());
1394
        self::assertEquals($sequence1InitialValue, $actualSequence1->getInitialValue());
1395
1396
        self::assertSame($sequence2Name, $actualSequence2->getName());
1397
        self::assertEquals($sequence2AllocationSize, $actualSequence2->getAllocationSize());
1398
        self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue());
1399
    }
1400
1401
    /**
1402
     * Returns potential escaped literals from all platforms combined.
1403
     *
1404
     * @see https://dev.mysql.com/doc/refman/5.7/en/string-literals.html
1405
     * @see http://www.sqlite.org/lang_expr.html
1406
     * @see https://www.postgresql.org/docs/9.6/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE
1407
     *
1408
     * @return array
1409
     */
1410
    private function getEscapedLiterals(): array
1411
    {
1412
        return [
1413
            ['An ASCII NUL (X\'00\')', "foo\\0bar"],
1414
            ['Single quote, C-style', "foo\\'bar"],
1415
            ['Single quote, doubled-style', "foo''bar"],
1416
            ['Double quote, C-style', 'foo\\"bar'],
1417
            ['Double quote, double-style', 'foo""bar'],
1418
            ['Backspace', 'foo\\bbar'],
1419
            ['New-line', 'foo\\nbar'],
1420
            ['Carriage return', 'foo\\rbar'],
1421
            ['Tab', 'foo\\tbar'],
1422
            ['ASCII 26 (Control+Z)', 'foo\\Zbar'],
1423
            ['Backslash (\)', 'foo\\\\bar'],
1424
            ['Percent (%)', 'foo\\%bar'],
1425
            ['Underscore (_)', 'foo\\_bar'],
1426
        ];
1427
    }
1428
1429
    private function createTableForDefaultValues(): void
1430
    {
1431
        $table = new Table('string_escaped_default_value');
1432
        foreach ($this->getEscapedLiterals() as $i => $literal) {
1433
            $table->addColumn('field' . $i, 'string', ['default' => $literal[1]]);
1434
        }
1435
1436
        $table->addColumn('def_foo', 'string');
1437
        $this->_sm->dropAndCreateTable($table);
1438
    }
1439
1440
    public function testEscapedDefaultValueCanBeIntrospected(): void
1441
    {
1442
        $this->createTableForDefaultValues();
1443
1444
        $onlineTable = $this->_sm->listTableDetails('string_escaped_default_value');
1445
        foreach ($this->getEscapedLiterals() as $i => $literal) {
1446
            self::assertSame($literal[1], $onlineTable->getColumn('field' . $i)->getDefault(), 'should be able introspect the value of default for: ' . $literal[0]);
1447
        }
1448
    }
1449
1450
    public function testEscapedDefaultValueCanBeInserted(): void
1451
    {
1452
        $this->createTableForDefaultValues();
1453
1454
        $this->_conn->insert('string_escaped_default_value', ['def_foo' => 'foo']);
1455
        $row = $this->_conn->fetchAssoc('SELECT * FROM string_escaped_default_value');
1456
        foreach ($this->getEscapedLiterals() as $i => $literal) {
1457
            self::assertSame($literal[1], $row['field' . $i], 'inserted default value should be the configured default value for: ' . $literal[0]);
1458
1459
        }
1460
    }
1461
}
1462