Completed
Pull Request — master (#3610)
by Sergei
03:27 queued 10s
created

testGetAlterTableSqlDispatchEvent()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 58
rs 8.9163
c 0
b 0
f 0
cc 1
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Platforms;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\DBAL\DBALException;
9
use Doctrine\DBAL\Events;
10
use Doctrine\DBAL\Platforms\AbstractPlatform;
11
use Doctrine\DBAL\Platforms\Keywords\KeywordList;
12
use Doctrine\DBAL\Schema\Column;
13
use Doctrine\DBAL\Schema\ColumnDiff;
14
use Doctrine\DBAL\Schema\Comparator;
15
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
16
use Doctrine\DBAL\Schema\Index;
17
use Doctrine\DBAL\Schema\Table;
18
use Doctrine\DBAL\Schema\TableDiff;
19
use Doctrine\DBAL\Schema\UniqueConstraint;
20
use Doctrine\DBAL\Types\Type;
21
use Doctrine\Tests\DbalTestCase;
22
use Doctrine\Tests\Types\CommentedType;
23
use function get_class;
24
use function implode;
25
use function sprintf;
26
use function str_repeat;
27
28
abstract class AbstractPlatformTestCase extends DbalTestCase
29
{
30
    /** @var AbstractPlatform */
31
    protected $platform;
32
33
    abstract public function createPlatform() : AbstractPlatform;
34
35
    protected function setUp() : void
36
    {
37
        $this->platform = $this->createPlatform();
38
    }
39
40
    /**
41
     * @group DDC-1360
42
     */
43
    public function testQuoteIdentifier() : void
44
    {
45
        if ($this->platform->getName() === 'mssql') {
46
            $this->markTestSkipped('Not working this way on mssql.');
47
        }
48
49
        $c = $this->platform->getIdentifierQuoteCharacter();
50
        self::assertEquals($c . 'test' . $c, $this->platform->quoteIdentifier('test'));
51
        self::assertEquals($c . 'test' . $c . '.' . $c . 'test' . $c, $this->platform->quoteIdentifier('test.test'));
52
        self::assertEquals(str_repeat($c, 4), $this->platform->quoteIdentifier($c));
53
    }
54
55
    /**
56
     * @group DDC-1360
57
     */
58
    public function testQuoteSingleIdentifier() : void
59
    {
60
        if ($this->platform->getName() === 'mssql') {
61
            $this->markTestSkipped('Not working this way on mssql.');
62
        }
63
64
        $c = $this->platform->getIdentifierQuoteCharacter();
65
        self::assertEquals($c . 'test' . $c, $this->platform->quoteSingleIdentifier('test'));
66
        self::assertEquals($c . 'test.test' . $c, $this->platform->quoteSingleIdentifier('test.test'));
67
        self::assertEquals(str_repeat($c, 4), $this->platform->quoteSingleIdentifier($c));
68
    }
69
70
    /**
71
     * @group DBAL-1029
72
     * @dataProvider getReturnsForeignKeyReferentialActionSQL
73
     */
74
    public function testReturnsForeignKeyReferentialActionSQL(string $action, string $expectedSQL) : void
75
    {
76
        self::assertSame($expectedSQL, $this->platform->getForeignKeyReferentialActionSQL($action));
77
    }
78
79
    /**
80
     * @return mixed[][]
81
     */
82
    public static function getReturnsForeignKeyReferentialActionSQL() : iterable
83
    {
84
        return [
85
            ['CASCADE', 'CASCADE'],
86
            ['SET NULL', 'SET NULL'],
87
            ['NO ACTION', 'NO ACTION'],
88
            ['RESTRICT', 'RESTRICT'],
89
            ['SET DEFAULT', 'SET DEFAULT'],
90
            ['CaScAdE', 'CASCADE'],
91
        ];
92
    }
93
94
    public function testGetInvalidForeignKeyReferentialActionSQL() : void
95
    {
96
        $this->expectException('InvalidArgumentException');
97
        $this->platform->getForeignKeyReferentialActionSQL('unknown');
98
    }
99
100
    public function testGetUnknownDoctrineMappingType() : void
101
    {
102
        $this->expectException(DBALException::class);
103
        $this->platform->getDoctrineTypeMapping('foobar');
104
    }
105
106
    public function testRegisterDoctrineMappingType() : void
107
    {
108
        $this->platform->registerDoctrineTypeMapping('foo', 'integer');
109
        self::assertEquals('integer', $this->platform->getDoctrineTypeMapping('foo'));
110
    }
111
112
    public function testRegisterUnknownDoctrineMappingType() : void
113
    {
114
        $this->expectException(DBALException::class);
115
        $this->platform->registerDoctrineTypeMapping('foo', 'bar');
116
    }
117
118
    /**
119
     * @group DBAL-2594
120
     */
121
    public function testRegistersCommentedDoctrineMappingTypeImplicitly() : void
122
    {
123
        if (! Type::hasType('my_commented')) {
124
            Type::addType('my_commented', CommentedType::class);
125
        }
126
127
        $type = Type::getType('my_commented');
128
        $this->platform->registerDoctrineTypeMapping('foo', 'my_commented');
129
130
        self::assertTrue($this->platform->isCommentedDoctrineType($type));
131
    }
132
133
    /**
134
     * @group DBAL-939
135
     * @dataProvider getIsCommentedDoctrineType
136
     */
137
    public function testIsCommentedDoctrineType(Type $type, bool $commented) : void
138
    {
139
        self::assertSame($commented, $this->platform->isCommentedDoctrineType($type));
140
    }
141
142
    /**
143
     * @return mixed[]
144
     */
145
    public function getIsCommentedDoctrineType() : iterable
146
    {
147
        $this->setUp();
148
149
        $data = [];
150
151
        foreach (Type::getTypesMap() as $typeName => $className) {
152
            $type = Type::getType($typeName);
153
154
            $data[$typeName] = [
155
                $type,
156
                $type->requiresSQLCommentHint($this->platform),
157
            ];
158
        }
159
160
        return $data;
161
    }
162
163
    public function testCreateWithNoColumns() : void
164
    {
165
        $table = new Table('test');
166
167
        $this->expectException(DBALException::class);
168
        $sql = $this->platform->getCreateTableSQL($table);
0 ignored issues
show
Unused Code introduced by
$sql is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
169
    }
170
171
    public function testGeneratesTableCreationSql() : void
172
    {
173
        $table = new Table('test');
174
        $table->addColumn('id', 'integer', ['notnull' => true, 'autoincrement' => true]);
175
        $table->addColumn('test', 'string', ['notnull' => false, 'length' => 255]);
176
        $table->setPrimaryKey(['id']);
177
178
        $sql = $this->platform->getCreateTableSQL($table);
179
        self::assertEquals($this->getGenerateTableSql(), $sql[0]);
180
    }
181
182
    abstract public function getGenerateTableSql() : string;
183
184
    public function testGenerateTableWithMultiColumnUniqueIndex() : void
185
    {
186
        $table = new Table('test');
187
        $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]);
188
        $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]);
189
        $table->addUniqueIndex(['foo', 'bar']);
190
191
        $sql = $this->platform->getCreateTableSQL($table);
192
        self::assertEquals($this->getGenerateTableWithMultiColumnUniqueIndexSql(), $sql);
193
    }
194
195
    /**
196
     * @return string[]
197
     */
198
    abstract public function getGenerateTableWithMultiColumnUniqueIndexSql() : array;
199
200
    public function testGeneratesIndexCreationSql() : void
201
    {
202
        $indexDef = new Index('my_idx', ['user_name', 'last_login']);
203
204
        self::assertEquals(
205
            $this->getGenerateIndexSql(),
206
            $this->platform->getCreateIndexSQL($indexDef, 'mytable')
207
        );
208
    }
209
210
    abstract public function getGenerateIndexSql() : string;
211
212
    public function testGeneratesUniqueIndexCreationSql() : void
213
    {
214
        $indexDef = new Index('index_name', ['test', 'test2'], true);
215
216
        $sql = $this->platform->getCreateIndexSQL($indexDef, 'test');
217
        self::assertEquals($this->getGenerateUniqueIndexSql(), $sql);
218
    }
219
220
    abstract public function getGenerateUniqueIndexSql() : string;
221
222
    public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() : void
223
    {
224
        $where            = 'test IS NULL AND test2 IS NOT NULL';
225
        $indexDef         = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]);
226
        $uniqueConstraint = new UniqueConstraint('name', ['test', 'test2'], [], []);
227
228
        $expected = ' WHERE ' . $where;
229
230
        $actuals = [];
231
232
        if ($this->supportsInlineIndexDeclaration()) {
233
            $actuals[] = $this->platform->getIndexDeclarationSQL('name', $indexDef);
234
        }
235
236
        $uniqueConstraintSQL = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueConstraint);
237
        $indexSQL            = $this->platform->getCreateIndexSQL($indexDef, 'table');
238
239
        $this->assertStringEndsNotWith($expected, $uniqueConstraintSQL, 'WHERE clause should NOT be present');
240
        if ($this->platform->supportsPartialIndexes()) {
241
            self::assertStringEndsWith($expected, $indexSQL, 'WHERE clause should be present');
242
        } else {
243
            self::assertStringEndsNotWith($expected, $indexSQL, 'WHERE clause should NOT be present');
244
        }
245
    }
246
247
    public function testGeneratesForeignKeyCreationSql() : void
248
    {
249
        $fk = new ForeignKeyConstraint(['fk_name_id'], 'other_table', ['id']);
250
251
        $sql = $this->platform->getCreateForeignKeySQL($fk, 'test');
252
        self::assertEquals($this->getGenerateForeignKeySql(), $sql);
253
    }
254
255
    abstract public function getGenerateForeignKeySql() : string;
256
257
    public function testGeneratesConstraintCreationSql() : void
258
    {
259
        $idx = new Index('constraint_name', ['test'], true, false);
260
        $sql = $this->platform->getCreateConstraintSQL($idx, 'test');
261
        self::assertEquals($this->getGenerateConstraintUniqueIndexSql(), $sql);
262
263
        $pk  = new Index('constraint_name', ['test'], true, true);
264
        $sql = $this->platform->getCreateConstraintSQL($pk, 'test');
265
        self::assertEquals($this->getGenerateConstraintPrimaryIndexSql(), $sql);
266
267
        $fk  = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk');
268
        $sql = $this->platform->getCreateConstraintSQL($fk, 'test');
269
        self::assertEquals($this->getGenerateConstraintForeignKeySql($fk), $sql);
270
    }
271
272
    public function testGeneratesForeignKeySqlOnlyWhenSupportingForeignKeys() : void
273
    {
274
        $fk = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk');
275
276
        if ($this->platform->supportsForeignKeyConstraints()) {
277
            self::assertIsString($this->platform->getCreateForeignKeySQL($fk, 'test'));
278
        } else {
279
            $this->expectException(DBALException::class);
280
            $this->platform->getCreateForeignKeySQL($fk, 'test');
281
        }
282
    }
283
284
    protected function getBitAndComparisonExpressionSql(string $value1, string $value2) : string
285
    {
286
        return '(' . $value1 . ' & ' . $value2 . ')';
287
    }
288
289
    /**
290
     * @group DDC-1213
291
     */
292
    public function testGeneratesBitAndComparisonExpressionSql() : void
293
    {
294
        $sql = $this->platform->getBitAndComparisonExpression('2', '4');
295
        self::assertEquals($this->getBitAndComparisonExpressionSql('2', '4'), $sql);
296
    }
297
298
    protected function getBitOrComparisonExpressionSql(string $value1, string $value2) : string
299
    {
300
        return '(' . $value1 . ' | ' . $value2 . ')';
301
    }
302
303
    /**
304
     * @group DDC-1213
305
     */
306
    public function testGeneratesBitOrComparisonExpressionSql() : void
307
    {
308
        $sql = $this->platform->getBitOrComparisonExpression('2', '4');
309
        self::assertEquals($this->getBitOrComparisonExpressionSql('2', '4'), $sql);
310
    }
311
312
    public function getGenerateConstraintUniqueIndexSql() : string
313
    {
314
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)';
315
    }
316
317
    public function getGenerateConstraintPrimaryIndexSql() : string
318
    {
319
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)';
320
    }
321
322
    public function getGenerateConstraintForeignKeySql(ForeignKeyConstraint $fk) : string
323
    {
324
        $quotedForeignTable = $fk->getQuotedForeignTableName($this->platform);
325
326
        return sprintf(
327
            'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES %s (id)',
328
            $quotedForeignTable
329
        );
330
    }
331
332
    /**
333
     * @return string[]
334
     */
335
    abstract public function getGenerateAlterTableSql() : array;
336
337
    public function testGeneratesTableAlterationSql() : void
338
    {
339
        $expectedSql = $this->getGenerateAlterTableSql();
340
341
        $table = new Table('mytable');
342
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
343
        $table->addColumn('foo', 'integer');
344
        $table->addColumn('bar', 'string');
345
        $table->addColumn('bloo', 'boolean');
346
        $table->setPrimaryKey(['id']);
347
348
        $tableDiff                        = new TableDiff('mytable');
349
        $tableDiff->fromTable             = $table;
350
        $tableDiff->newName               = 'userlist';
351
        $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['notnull' => false]);
352
        $tableDiff->removedColumns['foo'] = new Column('foo', Type::getType('integer'));
353
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
354
            'bar',
355
            new Column(
356
                'baz',
357
                Type::getType('string'),
358
                [
359
                    'length' => 255,
360
                    'default' => 'def',
361
                ]
362
            ),
363
            ['type', 'notnull', 'default']
364
        );
365
366
        $tableDiff->changedColumns['bloo'] = new ColumnDiff(
367
            'bloo',
368
            new Column(
369
                'bloo',
370
                Type::getType('boolean'),
371
                ['default' => false]
372
            ),
373
            ['type', 'notnull', 'default']
374
        );
375
376
        $sql = $this->platform->getAlterTableSQL($tableDiff);
377
378
        self::assertEquals($expectedSql, $sql);
379
    }
380
381
    public function testGetCustomColumnDeclarationSql() : void
382
    {
383
        $field = ['columnDefinition' => 'MEDIUMINT(6) UNSIGNED'];
384
        self::assertEquals('foo MEDIUMINT(6) UNSIGNED', $this->platform->getColumnDeclarationSQL('foo', $field));
385
    }
386
387
    public function testGetCreateTableSqlDispatchEvent() : void
388
    {
389
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetCreateTableSqlDispatchEvenListener'))
390
            ->addMethods(['onSchemaCreateTable', 'onSchemaCreateTableColumn'])
391
            ->getMock();
392
        $listenerMock
393
            ->expects($this->once())
394
            ->method('onSchemaCreateTable');
395
        $listenerMock
396
            ->expects($this->exactly(2))
397
            ->method('onSchemaCreateTableColumn');
398
399
        $eventManager = new EventManager();
400
        $eventManager->addEventListener([Events::onSchemaCreateTable, Events::onSchemaCreateTableColumn], $listenerMock);
401
402
        $this->platform->setEventManager($eventManager);
403
404
        $table = new Table('test');
405
        $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]);
406
        $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]);
407
408
        $this->platform->getCreateTableSQL($table);
409
    }
410
411
    public function testGetDropTableSqlDispatchEvent() : void
412
    {
413
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetDropTableSqlDispatchEventListener'))
414
            ->addMethods(['onSchemaDropTable'])
415
            ->getMock();
416
        $listenerMock
417
            ->expects($this->once())
418
            ->method('onSchemaDropTable');
419
420
        $eventManager = new EventManager();
421
        $eventManager->addEventListener([Events::onSchemaDropTable], $listenerMock);
422
423
        $this->platform->setEventManager($eventManager);
424
425
        $this->platform->getDropTableSQL('TABLE');
426
    }
427
428
    public function testGetAlterTableSqlDispatchEvent() : void
429
    {
430
        $events = [
431
            'onSchemaAlterTable',
432
            'onSchemaAlterTableAddColumn',
433
            'onSchemaAlterTableRemoveColumn',
434
            'onSchemaAlterTableChangeColumn',
435
            'onSchemaAlterTableRenameColumn',
436
        ];
437
438
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetAlterTableSqlDispatchEvenListener'))
439
            ->addMethods($events)
440
            ->getMock();
441
        $listenerMock
442
            ->expects($this->once())
443
            ->method('onSchemaAlterTable');
444
        $listenerMock
445
            ->expects($this->once())
446
            ->method('onSchemaAlterTableAddColumn');
447
        $listenerMock
448
            ->expects($this->once())
449
            ->method('onSchemaAlterTableRemoveColumn');
450
        $listenerMock
451
            ->expects($this->once())
452
            ->method('onSchemaAlterTableChangeColumn');
453
        $listenerMock
454
            ->expects($this->once())
455
            ->method('onSchemaAlterTableRenameColumn');
456
457
        $eventManager = new EventManager();
458
        $events       = [
459
            Events::onSchemaAlterTable,
460
            Events::onSchemaAlterTableAddColumn,
461
            Events::onSchemaAlterTableRemoveColumn,
462
            Events::onSchemaAlterTableChangeColumn,
463
            Events::onSchemaAlterTableRenameColumn,
464
        ];
465
        $eventManager->addEventListener($events, $listenerMock);
466
467
        $this->platform->setEventManager($eventManager);
468
469
        $table = new Table('mytable');
470
        $table->addColumn('removed', 'integer');
471
        $table->addColumn('changed', 'integer');
472
        $table->addColumn('renamed', 'integer');
473
474
        $tableDiff                            = new TableDiff('mytable');
475
        $tableDiff->fromTable                 = $table;
476
        $tableDiff->addedColumns['added']     = new Column('added', Type::getType('integer'), []);
477
        $tableDiff->removedColumns['removed'] = new Column('removed', Type::getType('integer'), []);
478
        $tableDiff->changedColumns['changed'] = new ColumnDiff(
479
            'changed',
480
            new Column('changed2', Type::getType('string'), ['length' => 255])
481
        );
482
        $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer'));
483
484
        $this->platform->getAlterTableSQL($tableDiff);
485
    }
486
487
    /**
488
     * @group DBAL-42
489
     */
490
    public function testCreateTableColumnComments() : void
491
    {
492
        $table = new Table('test');
493
        $table->addColumn('id', 'integer', ['comment' => 'This is a comment']);
494
        $table->setPrimaryKey(['id']);
495
496
        self::assertEquals($this->getCreateTableColumnCommentsSQL(), $this->platform->getCreateTableSQL($table));
497
    }
498
499
    /**
500
     * @group DBAL-42
501
     */
502
    public function testAlterTableColumnComments() : void
503
    {
504
        $tableDiff                        = new TableDiff('mytable');
505
        $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']);
506
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
507
            'foo',
508
            new Column('foo', Type::getType('string'), ['length' => 255]),
509
            ['comment']
510
        );
511
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
512
            'bar',
513
            new Column('baz', Type::getType('string'), [
514
                'length'  => 255,
515
                'comment' => 'B comment',
516
            ]),
517
            ['comment']
518
        );
519
520
        self::assertEquals($this->getAlterTableColumnCommentsSQL(), $this->platform->getAlterTableSQL($tableDiff));
521
    }
522
523
    public function testCreateTableColumnTypeComments() : void
524
    {
525
        $table = new Table('test');
526
        $table->addColumn('id', 'integer');
527
        $table->addColumn('data', 'array');
528
        $table->setPrimaryKey(['id']);
529
530
        self::assertEquals($this->getCreateTableColumnTypeCommentsSQL(), $this->platform->getCreateTableSQL($table));
531
    }
532
533
    /**
534
     * @return string[]
535
     */
536
    public function getCreateTableColumnCommentsSQL() : array
537
    {
538
        $this->markTestSkipped('Platform does not support Column comments.');
539
    }
540
541
    /**
542
     * @return string[]
543
     */
544
    public function getAlterTableColumnCommentsSQL() : array
545
    {
546
        $this->markTestSkipped('Platform does not support Column comments.');
547
    }
548
549
    /**
550
     * @return string[]
551
     */
552
    public function getCreateTableColumnTypeCommentsSQL() : array
553
    {
554
        $this->markTestSkipped('Platform does not support Column comments.');
555
    }
556
557
    public function testGetDefaultValueDeclarationSQL() : void
558
    {
559
        // non-timestamp value will get single quotes
560
        $field = [
561
            'type' => Type::getType('string'),
562
            'default' => 'non_timestamp',
563
        ];
564
565
        self::assertEquals(" DEFAULT 'non_timestamp'", $this->platform->getDefaultValueDeclarationSQL($field));
566
    }
567
568
    /**
569
     * @group 2859
570
     */
571
    public function testGetDefaultValueDeclarationSQLDateTime() : void
572
    {
573
        // timestamps on datetime types should not be quoted
574
        foreach (['datetime', 'datetimetz', 'datetime_immutable', 'datetimetz_immutable'] as $type) {
575
            $field = [
576
                'type'    => Type::getType($type),
577
                'default' => $this->platform->getCurrentTimestampSQL(),
578
            ];
579
580
            self::assertSame(
581
                ' DEFAULT ' . $this->platform->getCurrentTimestampSQL(),
582
                $this->platform->getDefaultValueDeclarationSQL($field)
583
            );
584
        }
585
    }
586
587
    public function testGetDefaultValueDeclarationSQLForIntegerTypes() : void
588
    {
589
        foreach (['bigint', 'integer', 'smallint'] as $type) {
590
            $field = [
591
                'type'    => Type::getType($type),
592
                'default' => 1,
593
            ];
594
595
            self::assertEquals(
596
                ' DEFAULT 1',
597
                $this->platform->getDefaultValueDeclarationSQL($field)
598
            );
599
        }
600
    }
601
602
    /**
603
     * @group 2859
604
     */
605
    public function testGetDefaultValueDeclarationSQLForDateType() : void
606
    {
607
        $currentDateSql = $this->platform->getCurrentDateSQL();
608
        foreach (['date', 'date_immutable'] as $type) {
609
            $field = [
610
                'type'    => Type::getType($type),
611
                'default' => $currentDateSql,
612
            ];
613
614
            self::assertSame(
615
                ' DEFAULT ' . $currentDateSql,
616
                $this->platform->getDefaultValueDeclarationSQL($field)
617
            );
618
        }
619
    }
620
621
    /**
622
     * @group DBAL-45
623
     */
624
    public function testKeywordList() : void
625
    {
626
        $keywordList = $this->platform->getReservedKeywordsList();
627
        self::assertInstanceOf(KeywordList::class, $keywordList);
628
629
        self::assertTrue($keywordList->isKeyword('table'));
630
    }
631
632
    /**
633
     * @group DBAL-374
634
     */
635
    public function testQuotedColumnInPrimaryKeyPropagation() : void
636
    {
637
        $table = new Table('`quoted`');
638
        $table->addColumn('create', 'string', ['length' => 255]);
639
        $table->setPrimaryKey(['create']);
640
641
        $sql = $this->platform->getCreateTableSQL($table);
642
        self::assertEquals($this->getQuotedColumnInPrimaryKeySQL(), $sql);
643
    }
644
645
    /**
646
     * @return string[]
647
     */
648
    abstract protected function getQuotedColumnInPrimaryKeySQL() : array;
649
650
    /**
651
     * @return string[]
652
     */
653
    abstract protected function getQuotedColumnInIndexSQL() : array;
654
655
    /**
656
     * @return string[]
657
     */
658
    abstract protected function getQuotedNameInIndexSQL() : array;
659
660
    /**
661
     * @return string[]
662
     */
663
    abstract protected function getQuotedColumnInForeignKeySQL() : array;
664
665
    /**
666
     * @group DBAL-374
667
     */
668
    public function testQuotedColumnInIndexPropagation() : void
669
    {
670
        $table = new Table('`quoted`');
671
        $table->addColumn('create', 'string', ['length' => 255]);
672
        $table->addIndex(['create']);
673
674
        $sql = $this->platform->getCreateTableSQL($table);
675
        self::assertEquals($this->getQuotedColumnInIndexSQL(), $sql);
676
    }
677
678
    public function testQuotedNameInIndexSQL() : void
679
    {
680
        $table = new Table('test');
681
        $table->addColumn('column1', 'string', ['length' => 255]);
682
        $table->addIndex(['column1'], '`key`');
683
684
        $sql = $this->platform->getCreateTableSQL($table);
685
        self::assertEquals($this->getQuotedNameInIndexSQL(), $sql);
686
    }
687
688
    /**
689
     * @group DBAL-374
690
     */
691
    public function testQuotedColumnInForeignKeyPropagation() : void
692
    {
693
        $table = new Table('`quoted`');
694
        $table->addColumn('create', 'string', ['length' => 255]);
695
        $table->addColumn('foo', 'string', ['length' => 255]);
696
        $table->addColumn('`bar`', 'string', ['length' => 255]);
697
698
        // Foreign table with reserved keyword as name (needs quotation).
699
        $foreignTable = new Table('foreign');
700
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
701
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
702
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
703
704
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_RESERVED_KEYWORD');
705
706
        // Foreign table with non-reserved keyword as name (does not need quotation).
707
        $foreignTable = new Table('foo');
708
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
709
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
710
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
711
712
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_NON_RESERVED_KEYWORD');
713
714
        // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
715
        $foreignTable = new Table('`foo-bar`');
716
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
717
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
718
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
719
720
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_INTENDED_QUOTATION');
721
722
        $sql = $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS);
723
        self::assertEquals($this->getQuotedColumnInForeignKeySQL(), $sql);
724
    }
725
726
    /**
727
     * @group DBAL-1051
728
     */
729
    public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : void
730
    {
731
        $constraint = new UniqueConstraint('select', ['foo'], [], []);
732
733
        self::assertSame(
734
            $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(),
735
            $this->platform->getUniqueConstraintDeclarationSQL('select', $constraint)
736
        );
737
    }
738
739
    abstract protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string;
740
741
    /**
742
     * @group DBAL-2270
743
     */
744
    public function testQuotesReservedKeywordInTruncateTableSQL() : void
745
    {
746
        self::assertSame(
747
            $this->getQuotesReservedKeywordInTruncateTableSQL(),
748
            $this->platform->getTruncateTableSQL('select')
749
        );
750
    }
751
752
    abstract protected function getQuotesReservedKeywordInTruncateTableSQL() : string;
753
754
    /**
755
     * @group DBAL-1051
756
     */
757
    public function testQuotesReservedKeywordInIndexDeclarationSQL() : void
758
    {
759
        $index = new Index('select', ['foo']);
760
761
        if (! $this->supportsInlineIndexDeclaration()) {
762
            $this->expectException(DBALException::class);
763
        }
764
765
        self::assertSame(
766
            $this->getQuotesReservedKeywordInIndexDeclarationSQL(),
767
            $this->platform->getIndexDeclarationSQL('select', $index)
768
        );
769
    }
770
771
    abstract protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string;
772
773
    protected function supportsInlineIndexDeclaration() : bool
774
    {
775
        return true;
776
    }
777
778
    public function testSupportsCommentOnStatement() : void
779
    {
780
        self::assertSame($this->supportsCommentOnStatement(), $this->platform->supportsCommentOnStatement());
781
    }
782
783
    protected function supportsCommentOnStatement() : bool
784
    {
785
        return false;
786
    }
787
788
    public function testGetCreateSchemaSQL() : void
789
    {
790
        $this->expectException(DBALException::class);
791
792
        $this->platform->getCreateSchemaSQL('schema');
793
    }
794
795
    /**
796
     * @group DBAL-585
797
     */
798
    public function testAlterTableChangeQuotedColumn() : void
799
    {
800
        $tableDiff                        = new TableDiff('mytable');
801
        $tableDiff->fromTable             = new Table('mytable');
802
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
803
            'select',
804
            new Column(
805
                'select',
806
                Type::getType('string'),
807
                ['length' => 255]
808
            ),
809
            ['type']
810
        );
811
812
        self::assertStringContainsString(
813
            $this->platform->quoteIdentifier('select'),
814
            implode(';', $this->platform->getAlterTableSQL($tableDiff))
815
        );
816
    }
817
818
    /**
819
     * @group DBAL-563
820
     */
821
    public function testUsesSequenceEmulatedIdentityColumns() : void
822
    {
823
        self::assertFalse($this->platform->usesSequenceEmulatedIdentityColumns());
824
    }
825
826
    /**
827
     * @group DBAL-563
828
     */
829
    public function testReturnsIdentitySequenceName() : void
830
    {
831
        $this->expectException(DBALException::class);
832
833
        $this->platform->getIdentitySequenceName('mytable', 'mycolumn');
834
    }
835
836
    public function testGetFixedLengthStringTypeDeclarationSQLNoLength() : void
837
    {
838
        self::assertSame(
839
            $this->getExpectedFixedLengthStringTypeDeclarationSQLNoLength(),
840
            $this->platform->getStringTypeDeclarationSQL(['fixed' => true])
841
        );
842
    }
843
844
    protected function getExpectedFixedLengthStringTypeDeclarationSQLNoLength() : string
845
    {
846
        return 'CHAR';
847
    }
848
849
    public function testGetFixedLengthStringTypeDeclarationSQLWithLength() : void
850
    {
851
        self::assertSame(
852
            $this->getExpectedFixedLengthStringTypeDeclarationSQLWithLength(),
853
            $this->platform->getStringTypeDeclarationSQL([
854
                'fixed' => true,
855
                'length' => 16,
856
            ])
857
        );
858
    }
859
860
    protected function getExpectedFixedLengthStringTypeDeclarationSQLWithLength() : string
861
    {
862
        return 'CHAR(16)';
863
    }
864
865
    public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void
866
    {
867
        self::assertSame(
868
            $this->getExpectedVariableLengthStringTypeDeclarationSQLNoLength(),
869
            $this->platform->getStringTypeDeclarationSQL([])
870
        );
871
    }
872
873
    protected function getExpectedVariableLengthStringTypeDeclarationSQLNoLength() : string
874
    {
875
        return 'VARCHAR';
876
    }
877
878
    public function testGetVariableLengthStringTypeDeclarationSQLWithLength() : void
879
    {
880
        self::assertSame(
881
            $this->getExpectedVariableLengthStringTypeDeclarationSQLWithLength(),
882
            $this->platform->getStringTypeDeclarationSQL(['length' => 16])
883
        );
884
    }
885
886
    protected function getExpectedVariableLengthStringTypeDeclarationSQLWithLength() : string
887
    {
888
        return 'VARCHAR(16)';
889
    }
890
891
    public function testGetFixedLengthBinaryTypeDeclarationSQLNoLength() : void
892
    {
893
        self::assertSame(
894
            $this->getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength(),
895
            $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])
896
        );
897
    }
898
899
    public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string
900
    {
901
        return 'BINARY';
902
    }
903
904
    public function testGetFixedLengthBinaryTypeDeclarationSQLWithLength() : void
905
    {
906
        self::assertSame(
907
            $this->getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength(),
908
            $this->platform->getBinaryTypeDeclarationSQL([
909
                'fixed' => true,
910
                'length' => 16,
911
            ])
912
        );
913
    }
914
915
    public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string
916
    {
917
        return 'BINARY(16)';
918
    }
919
920
    public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void
921
    {
922
        self::assertSame(
923
            $this->getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength(),
924
            $this->platform->getBinaryTypeDeclarationSQL([])
925
        );
926
    }
927
928
    public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string
929
    {
930
        return 'VARBINARY';
931
    }
932
933
    public function testGetVariableLengthBinaryTypeDeclarationSQLWithLength() : void
934
    {
935
        self::assertSame(
936
            $this->getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength(),
937
            $this->platform->getBinaryTypeDeclarationSQL(['length' => 16])
938
        );
939
    }
940
941
    public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string
942
    {
943
        return 'VARBINARY(16)';
944
    }
945
946
    /**
947
     * @group DBAL-553
948
     */
949
    public function hasNativeJsonType() : void
950
    {
951
        self::assertFalse($this->platform->hasNativeJsonType());
952
    }
953
954
    /**
955
     * @group DBAL-553
956
     */
957
    public function testReturnsJsonTypeDeclarationSQL() : void
958
    {
959
        $column = [
960
            'length'  => 666,
961
            'notnull' => true,
962
            'type'    => Type::getType('json'),
963
        ];
964
965
        self::assertSame(
966
            $this->platform->getClobTypeDeclarationSQL($column),
967
            $this->platform->getJsonTypeDeclarationSQL($column)
968
        );
969
    }
970
971
    /**
972
     * @group DBAL-234
973
     */
974
    public function testAlterTableRenameIndex() : void
975
    {
976
        $tableDiff            = new TableDiff('mytable');
977
        $tableDiff->fromTable = new Table('mytable');
978
        $tableDiff->fromTable->addColumn('id', 'integer');
979
        $tableDiff->fromTable->setPrimaryKey(['id']);
980
        $tableDiff->renamedIndexes = [
981
            'idx_foo' => new Index('idx_bar', ['id']),
982
        ];
983
984
        self::assertSame(
985
            $this->getAlterTableRenameIndexSQL(),
986
            $this->platform->getAlterTableSQL($tableDiff)
987
        );
988
    }
989
990
    /**
991
     * @return string[]
992
     *
993
     * @group DBAL-234
994
     */
995
    protected function getAlterTableRenameIndexSQL() : array
996
    {
997
        return [
998
            'DROP INDEX idx_foo',
999
            'CREATE INDEX idx_bar ON mytable (id)',
1000
        ];
1001
    }
1002
1003
    /**
1004
     * @group DBAL-234
1005
     */
1006
    public function testQuotesAlterTableRenameIndex() : void
1007
    {
1008
        $tableDiff            = new TableDiff('table');
1009
        $tableDiff->fromTable = new Table('table');
1010
        $tableDiff->fromTable->addColumn('id', 'integer');
1011
        $tableDiff->fromTable->setPrimaryKey(['id']);
1012
        $tableDiff->renamedIndexes = [
1013
            'create' => new Index('select', ['id']),
1014
            '`foo`'  => new Index('`bar`', ['id']),
1015
        ];
1016
1017
        self::assertSame(
1018
            $this->getQuotedAlterTableRenameIndexSQL(),
1019
            $this->platform->getAlterTableSQL($tableDiff)
1020
        );
1021
    }
1022
1023
    /**
1024
     * @return string[]
1025
     *
1026
     * @group DBAL-234
1027
     */
1028
    protected function getQuotedAlterTableRenameIndexSQL() : array
1029
    {
1030
        return [
1031
            'DROP INDEX "create"',
1032
            'CREATE INDEX "select" ON "table" (id)',
1033
            'DROP INDEX "foo"',
1034
            'CREATE INDEX "bar" ON "table" (id)',
1035
        ];
1036
    }
1037
1038
    /**
1039
     * @group DBAL-835
1040
     */
1041
    public function testQuotesAlterTableRenameColumn() : void
1042
    {
1043
        $fromTable = new Table('mytable');
1044
1045
        $fromTable->addColumn('unquoted1', 'integer', ['comment' => 'Unquoted 1']);
1046
        $fromTable->addColumn('unquoted2', 'integer', ['comment' => 'Unquoted 2']);
1047
        $fromTable->addColumn('unquoted3', 'integer', ['comment' => 'Unquoted 3']);
1048
1049
        $fromTable->addColumn('create', 'integer', ['comment' => 'Reserved keyword 1']);
1050
        $fromTable->addColumn('table', 'integer', ['comment' => 'Reserved keyword 2']);
1051
        $fromTable->addColumn('select', 'integer', ['comment' => 'Reserved keyword 3']);
1052
1053
        $fromTable->addColumn('`quoted1`', 'integer', ['comment' => 'Quoted 1']);
1054
        $fromTable->addColumn('`quoted2`', 'integer', ['comment' => 'Quoted 2']);
1055
        $fromTable->addColumn('`quoted3`', 'integer', ['comment' => 'Quoted 3']);
1056
1057
        $toTable = new Table('mytable');
1058
1059
        $toTable->addColumn('unquoted', 'integer', ['comment' => 'Unquoted 1']); // unquoted -> unquoted
1060
        $toTable->addColumn('where', 'integer', ['comment' => 'Unquoted 2']); // unquoted -> reserved keyword
1061
        $toTable->addColumn('`foo`', 'integer', ['comment' => 'Unquoted 3']); // unquoted -> quoted
1062
1063
        $toTable->addColumn('reserved_keyword', 'integer', ['comment' => 'Reserved keyword 1']); // reserved keyword -> unquoted
1064
        $toTable->addColumn('from', 'integer', ['comment' => 'Reserved keyword 2']); // reserved keyword -> reserved keyword
1065
        $toTable->addColumn('`bar`', 'integer', ['comment' => 'Reserved keyword 3']); // reserved keyword -> quoted
1066
1067
        $toTable->addColumn('quoted', 'integer', ['comment' => 'Quoted 1']); // quoted -> unquoted
1068
        $toTable->addColumn('and', 'integer', ['comment' => 'Quoted 2']); // quoted -> reserved keyword
1069
        $toTable->addColumn('`baz`', 'integer', ['comment' => 'Quoted 3']); // quoted -> quoted
1070
1071
        $comparator = new Comparator();
1072
1073
        $diff = $comparator->diffTable($fromTable, $toTable);
1074
1075
        self::assertNotNull($diff);
1076
1077
        self::assertEquals(
1078
            $this->getQuotedAlterTableRenameColumnSQL(),
1079
            $this->platform->getAlterTableSQL($diff)
0 ignored issues
show
Bug introduced by
It seems like $diff defined by $comparator->diffTable($fromTable, $toTable) on line 1073 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1080
        );
1081
    }
1082
1083
    /**
1084
     * Returns SQL statements for {@link testQuotesAlterTableRenameColumn}.
1085
     *
1086
     * @return string[]
1087
     *
1088
     * @group DBAL-835
1089
     */
1090
    abstract protected function getQuotedAlterTableRenameColumnSQL() : array;
1091
1092
    /**
1093
     * @group DBAL-835
1094
     */
1095
    public function testQuotesAlterTableChangeColumnLength() : void
1096
    {
1097
        $fromTable = new Table('mytable');
1098
1099
        $fromTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 10]);
1100
        $fromTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 10]);
1101
        $fromTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 10]);
1102
1103
        $fromTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 10]);
1104
        $fromTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 10]);
1105
        $fromTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 10]);
1106
1107
        $toTable = new Table('mytable');
1108
1109
        $toTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 255]);
1110
        $toTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 255]);
1111
        $toTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 255]);
1112
1113
        $toTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 255]);
1114
        $toTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 255]);
1115
        $toTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 255]);
1116
1117
        $comparator = new Comparator();
1118
1119
        $diff = $comparator->diffTable($fromTable, $toTable);
1120
1121
        self::assertNotNull($diff);
1122
1123
        self::assertEquals(
1124
            $this->getQuotedAlterTableChangeColumnLengthSQL(),
1125
            $this->platform->getAlterTableSQL($diff)
0 ignored issues
show
Bug introduced by
It seems like $diff defined by $comparator->diffTable($fromTable, $toTable) on line 1119 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1126
        );
1127
    }
1128
1129
    /**
1130
     * Returns SQL statements for {@link testQuotesAlterTableChangeColumnLength}.
1131
     *
1132
     * @return string[]
1133
     *
1134
     * @group DBAL-835
1135
     */
1136
    abstract protected function getQuotedAlterTableChangeColumnLengthSQL() : array;
1137
1138
    /**
1139
     * @group DBAL-807
1140
     */
1141
    public function testAlterTableRenameIndexInSchema() : void
1142
    {
1143
        $tableDiff            = new TableDiff('myschema.mytable');
1144
        $tableDiff->fromTable = new Table('myschema.mytable');
1145
        $tableDiff->fromTable->addColumn('id', 'integer');
1146
        $tableDiff->fromTable->setPrimaryKey(['id']);
1147
        $tableDiff->renamedIndexes = [
1148
            'idx_foo' => new Index('idx_bar', ['id']),
1149
        ];
1150
1151
        self::assertSame(
1152
            $this->getAlterTableRenameIndexInSchemaSQL(),
1153
            $this->platform->getAlterTableSQL($tableDiff)
1154
        );
1155
    }
1156
1157
    /**
1158
     * @return string[]
1159
     *
1160
     * @group DBAL-807
1161
     */
1162
    protected function getAlterTableRenameIndexInSchemaSQL() : array
1163
    {
1164
        return [
1165
            'DROP INDEX idx_foo',
1166
            'CREATE INDEX idx_bar ON myschema.mytable (id)',
1167
        ];
1168
    }
1169
1170
    /**
1171
     * @group DBAL-807
1172
     */
1173
    public function testQuotesAlterTableRenameIndexInSchema() : void
1174
    {
1175
        $tableDiff            = new TableDiff('`schema`.table');
1176
        $tableDiff->fromTable = new Table('`schema`.table');
1177
        $tableDiff->fromTable->addColumn('id', 'integer');
1178
        $tableDiff->fromTable->setPrimaryKey(['id']);
1179
        $tableDiff->renamedIndexes = [
1180
            'create' => new Index('select', ['id']),
1181
            '`foo`'  => new Index('`bar`', ['id']),
1182
        ];
1183
1184
        self::assertSame(
1185
            $this->getQuotedAlterTableRenameIndexInSchemaSQL(),
1186
            $this->platform->getAlterTableSQL($tableDiff)
1187
        );
1188
    }
1189
1190
    /**
1191
     * @return string[]
1192
     *
1193
     * @group DBAL-234
1194
     */
1195
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
1196
    {
1197
        return [
1198
            'DROP INDEX "schema"."create"',
1199
            'CREATE INDEX "select" ON "schema"."table" (id)',
1200
            'DROP INDEX "schema"."foo"',
1201
            'CREATE INDEX "bar" ON "schema"."table" (id)',
1202
        ];
1203
    }
1204
1205
    /**
1206
     * @group DBAL-1237
1207
     */
1208
    public function testQuotesDropForeignKeySQL() : void
1209
    {
1210
        if (! $this->platform->supportsForeignKeyConstraints()) {
1211
            $this->markTestSkipped(
1212
                sprintf('%s does not support foreign key constraints.', get_class($this->platform))
1213
            );
1214
        }
1215
1216
        $tableName      = 'table';
1217
        $table          = new Table($tableName);
1218
        $foreignKeyName = 'select';
1219
        $foreignKey     = new ForeignKeyConstraint([], 'foo', [], 'select');
1220
        $expectedSql    = $this->getQuotesDropForeignKeySQL();
1221
1222
        self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKeyName, $tableName));
1223
        self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKey, $table));
1224
    }
1225
1226
    protected function getQuotesDropForeignKeySQL() : string
1227
    {
1228
        return 'ALTER TABLE "table" DROP FOREIGN KEY "select"';
1229
    }
1230
1231
    /**
1232
     * @group DBAL-1237
1233
     */
1234
    public function testQuotesDropConstraintSQL() : void
1235
    {
1236
        $tableName      = 'table';
1237
        $table          = new Table($tableName);
1238
        $constraintName = 'select';
1239
        $constraint     = new ForeignKeyConstraint([], 'foo', [], 'select');
1240
        $expectedSql    = $this->getQuotesDropConstraintSQL();
1241
1242
        self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraintName, $tableName));
1243
        self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraint, $table));
1244
    }
1245
1246
    protected function getQuotesDropConstraintSQL() : string
1247
    {
1248
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
1249
    }
1250
1251
    protected function getStringLiteralQuoteCharacter() : string
1252
    {
1253
        return "'";
1254
    }
1255
1256
    public function testGetStringLiteralQuoteCharacter() : void
1257
    {
1258
        self::assertSame($this->getStringLiteralQuoteCharacter(), $this->platform->getStringLiteralQuoteCharacter());
1259
    }
1260
1261
    protected function getQuotedCommentOnColumnSQLWithoutQuoteCharacter() : string
1262
    {
1263
        return "COMMENT ON COLUMN mytable.id IS 'This is a comment'";
1264
    }
1265
1266
    public function testGetCommentOnColumnSQLWithoutQuoteCharacter() : void
1267
    {
1268
        self::assertEquals(
1269
            $this->getQuotedCommentOnColumnSQLWithoutQuoteCharacter(),
1270
            $this->platform->getCommentOnColumnSQL('mytable', 'id', 'This is a comment')
1271
        );
1272
    }
1273
1274
    protected function getQuotedCommentOnColumnSQLWithQuoteCharacter() : string
1275
    {
1276
        return "COMMENT ON COLUMN mytable.id IS 'It''s a quote !'";
1277
    }
1278
1279
    public function testGetCommentOnColumnSQLWithQuoteCharacter() : void
1280
    {
1281
        $c = $this->getStringLiteralQuoteCharacter();
1282
1283
        self::assertEquals(
1284
            $this->getQuotedCommentOnColumnSQLWithQuoteCharacter(),
1285
            $this->platform->getCommentOnColumnSQL('mytable', 'id', 'It' . $c . 's a quote !')
1286
        );
1287
    }
1288
1289
    /**
1290
     * @see testGetCommentOnColumnSQL
1291
     *
1292
     * @return string[]
1293
     */
1294
    abstract protected function getCommentOnColumnSQL() : array;
1295
1296
    /**
1297
     * @group DBAL-1004
1298
     */
1299
    public function testGetCommentOnColumnSQL() : void
1300
    {
1301
        self::assertSame(
1302
            $this->getCommentOnColumnSQL(),
1303
            [
1304
                $this->platform->getCommentOnColumnSQL('foo', 'bar', 'comment'), // regular identifiers
1305
                $this->platform->getCommentOnColumnSQL('`Foo`', '`BAR`', 'comment'), // explicitly quoted identifiers
1306
                $this->platform->getCommentOnColumnSQL('select', 'from', 'comment'), // reserved keyword identifiers
1307
            ]
1308
        );
1309
    }
1310
1311
    /**
1312
     * @group DBAL-1176
1313
     * @dataProvider getGeneratesInlineColumnCommentSQL
1314
     */
1315
    public function testGeneratesInlineColumnCommentSQL(?string $comment, string $expectedSql) : void
1316
    {
1317
        if (! $this->platform->supportsInlineColumnComments()) {
1318
            $this->markTestSkipped(sprintf('%s does not support inline column comments.', get_class($this->platform)));
1319
        }
1320
1321
        self::assertSame($expectedSql, $this->platform->getInlineColumnCommentSQL($comment));
1322
    }
1323
1324
    /**
1325
     * @return mixed[][]
1326
     */
1327
    public static function getGeneratesInlineColumnCommentSQL() : iterable
1328
    {
1329
        return [
1330
            'regular comment' => ['Regular comment', static::getInlineColumnRegularCommentSQL()],
1331
            'comment requiring escaping' => [
1332
                sprintf(
1333
                    'Using inline comment delimiter %s works',
1334
                    static::getInlineColumnCommentDelimiter()
1335
                ),
1336
                static::getInlineColumnCommentRequiringEscapingSQL(),
1337
            ],
1338
            'empty comment' => ['', static::getInlineColumnEmptyCommentSQL()],
1339
        ];
1340
    }
1341
1342
    protected static function getInlineColumnCommentDelimiter() : string
1343
    {
1344
        return "'";
1345
    }
1346
1347
    protected static function getInlineColumnRegularCommentSQL() : string
1348
    {
1349
        return "COMMENT 'Regular comment'";
1350
    }
1351
1352
    protected static function getInlineColumnCommentRequiringEscapingSQL() : string
1353
    {
1354
        return "COMMENT 'Using inline comment delimiter '' works'";
1355
    }
1356
1357
    protected static function getInlineColumnEmptyCommentSQL() : string
1358
    {
1359
        return "COMMENT ''";
1360
    }
1361
1362
    protected function getQuotedStringLiteralWithoutQuoteCharacter() : string
1363
    {
1364
        return "'No quote'";
1365
    }
1366
1367
    protected function getQuotedStringLiteralWithQuoteCharacter() : string
1368
    {
1369
        return "'It''s a quote'";
1370
    }
1371
1372
    protected function getQuotedStringLiteralQuoteCharacter() : string
1373
    {
1374
        return "''''";
1375
    }
1376
1377
    /**
1378
     * @group DBAL-1176
1379
     */
1380
    public function testThrowsExceptionOnGeneratingInlineColumnCommentSQLIfUnsupported() : void
1381
    {
1382
        if ($this->platform->supportsInlineColumnComments()) {
1383
            $this->markTestSkipped(sprintf('%s supports inline column comments.', get_class($this->platform)));
1384
        }
1385
1386
        $this->expectException(DBALException::class);
1387
        $this->expectExceptionMessage('Operation "Doctrine\\DBAL\\Platforms\\AbstractPlatform::getInlineColumnCommentSQL" is not supported by platform.');
1388
        $this->expectExceptionCode(0);
1389
1390
        $this->platform->getInlineColumnCommentSQL('unsupported');
1391
    }
1392
1393
    public function testQuoteStringLiteral() : void
1394
    {
1395
        $c = $this->getStringLiteralQuoteCharacter();
1396
1397
        self::assertEquals(
1398
            $this->getQuotedStringLiteralWithoutQuoteCharacter(),
1399
            $this->platform->quoteStringLiteral('No quote')
1400
        );
1401
        self::assertEquals(
1402
            $this->getQuotedStringLiteralWithQuoteCharacter(),
1403
            $this->platform->quoteStringLiteral('It' . $c . 's a quote')
1404
        );
1405
        self::assertEquals(
1406
            $this->getQuotedStringLiteralQuoteCharacter(),
1407
            $this->platform->quoteStringLiteral($c)
1408
        );
1409
    }
1410
1411
    /**
1412
     * @group DBAL-423
1413
     */
1414
    public function testReturnsGuidTypeDeclarationSQL() : void
1415
    {
1416
        $this->expectException(DBALException::class);
1417
1418
        $this->platform->getGuidTypeDeclarationSQL([]);
1419
    }
1420
1421
    /**
1422
     * @group DBAL-1010
1423
     */
1424
    public function testGeneratesAlterTableRenameColumnSQL() : void
1425
    {
1426
        $table = new Table('foo');
1427
        $table->addColumn(
1428
            'bar',
1429
            'integer',
1430
            ['notnull' => true, 'default' => 666, 'comment' => 'rename test']
1431
        );
1432
1433
        $tableDiff                        = new TableDiff('foo');
1434
        $tableDiff->fromTable             = $table;
1435
        $tableDiff->renamedColumns['bar'] = new Column(
1436
            'baz',
1437
            Type::getType('integer'),
1438
            ['notnull' => true, 'default' => 666, 'comment' => 'rename test']
1439
        );
1440
1441
        self::assertSame($this->getAlterTableRenameColumnSQL(), $this->platform->getAlterTableSQL($tableDiff));
1442
    }
1443
1444
    /**
1445
     * @return string[]
1446
     */
1447
    abstract public function getAlterTableRenameColumnSQL() : array;
1448
1449
    /**
1450
     * @group DBAL-1016
1451
     */
1452
    public function testQuotesTableIdentifiersInAlterTableSQL() : void
1453
    {
1454
        $table = new Table('"foo"');
1455
        $table->addColumn('id', 'integer');
1456
        $table->addColumn('fk', 'integer');
1457
        $table->addColumn('fk2', 'integer');
1458
        $table->addColumn('fk3', 'integer');
1459
        $table->addColumn('bar', 'integer');
1460
        $table->addColumn('baz', 'integer');
1461
        $table->addForeignKeyConstraint('fk_table', ['fk'], ['id'], [], 'fk1');
1462
        $table->addForeignKeyConstraint('fk_table', ['fk2'], ['id'], [], 'fk2');
1463
1464
        $tableDiff                        = new TableDiff('"foo"');
1465
        $tableDiff->fromTable             = $table;
1466
        $tableDiff->newName               = 'table';
1467
        $tableDiff->addedColumns['bloo']  = new Column('bloo', Type::getType('integer'));
1468
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
1469
            'bar',
1470
            new Column('bar', Type::getType('integer'), ['notnull' => false]),
1471
            ['notnull'],
1472
            $table->getColumn('bar')
1473
        );
1474
        $tableDiff->renamedColumns['id']  = new Column('war', Type::getType('integer'));
1475
        $tableDiff->removedColumns['baz'] = new Column('baz', Type::getType('integer'));
1476
        $tableDiff->addedForeignKeys[]    = new ForeignKeyConstraint(['fk3'], 'fk_table', ['id'], 'fk_add');
1477
        $tableDiff->changedForeignKeys[]  = new ForeignKeyConstraint(['fk2'], 'fk_table2', ['id'], 'fk2');
1478
        $tableDiff->removedForeignKeys[]  = new ForeignKeyConstraint(['fk'], 'fk_table', ['id'], 'fk1');
1479
1480
        self::assertSame(
1481
            $this->getQuotesTableIdentifiersInAlterTableSQL(),
1482
            $this->platform->getAlterTableSQL($tableDiff)
1483
        );
1484
    }
1485
1486
    /**
1487
     * @return string[]
1488
     */
1489
    abstract protected function getQuotesTableIdentifiersInAlterTableSQL() : array;
1490
1491
    /**
1492
     * @group DBAL-1090
1493
     */
1494
    public function testAlterStringToFixedString() : void
1495
    {
1496
        $table = new Table('mytable');
1497
        $table->addColumn('name', 'string', ['length' => 2]);
1498
1499
        $tableDiff            = new TableDiff('mytable');
1500
        $tableDiff->fromTable = $table;
1501
1502
        $tableDiff->changedColumns['name'] = new ColumnDiff(
1503
            'name',
1504
            new Column(
1505
                'name',
1506
                Type::getType('string'),
1507
                ['fixed' => true, 'length' => 2]
1508
            ),
1509
            ['fixed']
1510
        );
1511
1512
        $sql = $this->platform->getAlterTableSQL($tableDiff);
1513
1514
        $expectedSql = $this->getAlterStringToFixedStringSQL();
1515
1516
        self::assertEquals($expectedSql, $sql);
1517
    }
1518
1519
    /**
1520
     * @return string[]
1521
     */
1522
    abstract protected function getAlterStringToFixedStringSQL() : array;
1523
1524
    /**
1525
     * @group DBAL-1062
1526
     */
1527
    public function testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : void
1528
    {
1529
        $foreignTable = new Table('foreign_table');
1530
        $foreignTable->addColumn('id', 'integer');
1531
        $foreignTable->setPrimaryKey(['id']);
1532
1533
        $primaryTable = new Table('mytable');
1534
        $primaryTable->addColumn('foo', 'integer');
1535
        $primaryTable->addColumn('bar', 'integer');
1536
        $primaryTable->addColumn('baz', 'integer');
1537
        $primaryTable->addIndex(['foo'], 'idx_foo');
1538
        $primaryTable->addIndex(['bar'], 'idx_bar');
1539
        $primaryTable->addForeignKeyConstraint($foreignTable, ['foo'], ['id'], [], 'fk_foo');
1540
        $primaryTable->addForeignKeyConstraint($foreignTable, ['bar'], ['id'], [], 'fk_bar');
1541
1542
        $tableDiff                            = new TableDiff('mytable');
1543
        $tableDiff->fromTable                 = $primaryTable;
1544
        $tableDiff->renamedIndexes['idx_foo'] = new Index('idx_foo_renamed', ['foo']);
1545
1546
        self::assertSame(
1547
            $this->getGeneratesAlterTableRenameIndexUsedByForeignKeySQL(),
1548
            $this->platform->getAlterTableSQL($tableDiff)
1549
        );
1550
    }
1551
1552
    /**
1553
     * @return string[]
1554
     */
1555
    abstract protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array;
1556
1557
    /**
1558
     * @param mixed[] $column
1559
     *
1560
     * @group DBAL-1082
1561
     * @dataProvider getGeneratesDecimalTypeDeclarationSQL
1562
     */
1563
    public function testGeneratesDecimalTypeDeclarationSQL(array $column, string $expectedSql) : void
1564
    {
1565
        self::assertSame($expectedSql, $this->platform->getDecimalTypeDeclarationSQL($column));
1566
    }
1567
1568
    /**
1569
     * @return mixed[][]
1570
     */
1571
    public static function getGeneratesDecimalTypeDeclarationSQL() : iterable
1572
    {
1573
        return [
1574
            [[], 'NUMERIC(10, 0)'],
1575
            [['unsigned' => true], 'NUMERIC(10, 0)'],
1576
            [['unsigned' => false], 'NUMERIC(10, 0)'],
1577
            [['precision' => 5], 'NUMERIC(5, 0)'],
1578
            [['scale' => 5], 'NUMERIC(10, 5)'],
1579
            [['precision' => 8, 'scale' => 2], 'NUMERIC(8, 2)'],
1580
        ];
1581
    }
1582
1583
    /**
1584
     * @param mixed[] $column
1585
     *
1586
     * @group DBAL-1082
1587
     * @dataProvider getGeneratesFloatDeclarationSQL
1588
     */
1589
    public function testGeneratesFloatDeclarationSQL(array $column, string $expectedSql) : void
1590
    {
1591
        self::assertSame($expectedSql, $this->platform->getFloatDeclarationSQL($column));
1592
    }
1593
1594
    /**
1595
     * @return mixed[][]
1596
     */
1597
    public static function getGeneratesFloatDeclarationSQL() : iterable
1598
    {
1599
        return [
1600
            [[], 'DOUBLE PRECISION'],
1601
            [['unsigned' => true], 'DOUBLE PRECISION'],
1602
            [['unsigned' => false], 'DOUBLE PRECISION'],
1603
            [['precision' => 5], 'DOUBLE PRECISION'],
1604
            [['scale' => 5], 'DOUBLE PRECISION'],
1605
            [['precision' => 8, 'scale' => 2], 'DOUBLE PRECISION'],
1606
        ];
1607
    }
1608
1609
    public function testItEscapesStringsForLike() : void
1610
    {
1611
        self::assertSame(
1612
            '\_25\% off\_ your next purchase \\\\o/',
1613
            $this->platform->escapeStringForLike('_25% off_ your next purchase \o/', '\\')
1614
        );
1615
    }
1616
1617
    public function testZeroOffsetWithoutLimitIsIgnored() : void
1618
    {
1619
        $query = 'SELECT * FROM user';
1620
1621
        self::assertSame(
1622
            $query,
1623
            $this->platform->modifyLimitQuery($query, null, 0)
1624
        );
1625
    }
1626
}
1627