Failed Conditions
Pull Request — 3.0.x (#3980)
by Guilherme
07:55
created

AbstractPlatformTestCase   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 1515
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 610
dl 0
loc 1515
rs 1.99
c 0
b 0
f 0
wmc 124

110 Methods

Rating   Name   Duplication   Size   Complexity  
A getReturnsForeignKeyReferentialActionSQL() 0 9 1
A testReturnsForeignKeyReferentialActionSQL() 0 3 1
A testGeneratesIndexCreationSql() 0 7 1
A testGeneratesForeignKeyCreationSql() 0 6 1
A getIsCommentedDoctrineType() 0 16 2
A testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() 0 24 4
A testRegisterDoctrineMappingType() 0 4 1
A testCreateWithNoColumns() 0 6 1
A testGeneratesTableCreationSql() 0 9 1
A testIsCommentedDoctrineType() 0 3 1
A testGenerateTableWithMultiColumnUniqueIndex() 0 9 1
A setUp() 0 3 1
A testRegisterUnknownDoctrineMappingType() 0 4 1
A testGetUnknownDoctrineMappingType() 0 4 1
A testQuoteSingleIdentifier() 0 10 2
A testGeneratesUniqueIndexCreationSql() 0 6 1
A testRegistersCommentedDoctrineMappingTypeImplicitly() 0 6 1
A testGetInvalidForeignKeyReferentialActionSQL() 0 4 1
A testQuoteIdentifier() 0 10 2
A testGeneratesFloatDeclarationSQL() 0 3 1
A testQuotesTableIdentifiersInAlterTableSQL() 0 31 1
A getInlineColumnCommentRequiringEscapingSQL() 0 3 1
A testAlterTableRenameIndex() 0 13 1
A testUsesSequenceEmulatedIdentityColumns() 0 3 1
A getGenerateConstraintForeignKeySql() 0 7 1
A testKeywordList() 0 6 1
A testGetSequencePrefixWithSchema() 0 3 1
A testAlterTableRenameIndexInSchema() 0 13 1
A getInlineColumnCommentDelimiter() 0 3 1
A testQuotedNameInIndexSQL() 0 8 1
A testGetDropTableSqlDispatchEvent() 0 15 1
A testReturnsBinaryTypeDeclarationSQL() 0 5 1
A testQuotesAlterTableRenameColumn() 0 35 1
A testQuotesAlterTableChangeColumnLength() 0 27 1
A testQuoteStringLiteral() 0 15 1
A testQuotesDropForeignKeySQL() 0 16 2
A testReturnsIdentitySequenceName() 0 5 1
A testGetSequencePrefixWithoutSchema() 0 3 1
A getGenerateConstraintUniqueIndexSql() 0 3 1
A testReturnsGuidTypeDeclarationSQL() 0 5 1
A getBinaryDefaultLength() 0 3 1
A testGetCommentOnColumnSQL() 0 8 1
A getGenerateConstraintPrimaryIndexSql() 0 3 1
A testGetStringLiteralQuoteCharacter() 0 3 1
A getCreateTableColumnTypeCommentsSQL() 0 3 1
A getInlineColumnRegularCommentSQL() 0 3 1
A getQuotedAlterTableRenameIndexSQL() 0 7 1
A supportsInlineIndexDeclaration() 0 3 1
A testGetCommentOnColumnSQLWithoutQuoteCharacter() 0 5 1
A getQuotedAlterTableRenameIndexInSchemaSQL() 0 7 1
A testAlterTableColumnComments() 0 23 1
A getBitAndComparisonExpressionSql() 0 3 1
A testGetCustomColumnDeclarationSql() 0 4 1
A getQuotesDropForeignKeySQL() 0 3 1
A testQuotesDropConstraintSQL() 0 10 1
A getQuotedStringLiteralQuoteCharacter() 0 3 1
A testReturnsBinaryMaxLength() 0 3 1
A testGetDefaultValueDeclarationSQLForIntegerTypes() 0 11 2
A getStringLiteralQuoteCharacter() 0 3 1
A getGeneratesInlineColumnCommentSQL() 0 12 1
A testItEscapesStringsForLike() 0 5 1
A testQuotesAlterTableRenameIndexInSchema() 0 14 1
A supportsCommentOnStatement() 0 3 1
A testGeneratesBitOrComparisonExpressionSql() 0 4 1
A testGeneratesBitAndComparisonExpressionSql() 0 4 1
A getQuotedStringLiteralWithQuoteCharacter() 0 3 1
A testGetCommentOnColumnSQLWithQuoteCharacter() 0 7 1
A testGeneratesConstraintCreationSql() 0 17 2
A getInlineColumnEmptyCommentSQL() 0 3 1
A testSupportsCommentOnStatement() 0 3 1
A testQuotedColumnInPrimaryKeyPropagation() 0 8 1
A testGetDefaultValueDeclarationSQL() 0 9 1
A getBitOrComparisonExpressionSql() 0 3 1
A testReturnsBinaryDefaultLength() 0 3 1
A testGetCreateSchemaSQL() 0 5 1
A getBinaryMaxLength() 0 3 1
A testCreateTableColumnComments() 0 7 1
A getGeneratesFloatDeclarationSQL() 0 9 1
A getQuotesDropConstraintSQL() 0 3 1
A testGetDefaultValueDeclarationSQLDateTime() 0 12 2
A testGetAlterTableSqlDispatchEvent() 0 62 1
A testReturnsJsonTypeDeclarationSQL() 0 11 1
A testThrowsExceptionOnGeneratingInlineColumnCommentSQLIfUnsupported() 0 11 2
A testReturnsBinaryTypeLongerThanMaxDeclarationSQL() 0 3 1
A testGeneratesTableAlterationSql() 0 38 1
A getAlterTableColumnCommentsSQL() 0 3 1
A testQuotesReservedKeywordInIndexDeclarationSQL() 0 11 2
A getQuotedCommentOnColumnSQLWithQuoteCharacter() 0 3 1
A testGetCreateTableSqlDispatchEvent() 0 22 1
A getQuotedStringLiteralWithoutQuoteCharacter() 0 3 1
A testZeroOffsetWithoutLimitIsIgnored() 0 7 1
A testAlterStringToFixedString() 0 23 1
A getAlterTableRenameIndexSQL() 0 5 1
A testGeneratesAlterTableRenameColumnSQL() 0 18 1
A testGeneratesDecimalTypeDeclarationSQL() 0 3 1
A getQuotedCommentOnColumnSQLWithoutQuoteCharacter() 0 3 1
A testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() 0 7 1
A hasNativeJsonType() 0 3 1
A testAlterTableChangeQuotedColumn() 0 16 1
A getAlterTableRenameIndexInSchemaSQL() 0 5 1
A testQuotedColumnInForeignKeyPropagation() 0 33 1
A testGetDefaultValueDeclarationSQLForDateType() 0 12 2
A getCreateTableColumnCommentsSQL() 0 3 1
A getGeneratesDecimalTypeDeclarationSQL() 0 9 1
A testQuotedColumnInIndexPropagation() 0 8 1
A testQuotesAlterTableRenameIndex() 0 14 1
A testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() 0 22 1
A testGeneratesInlineColumnCommentSQL() 0 7 2
A testQuotesReservedKeywordInTruncateTableSQL() 0 5 1
A testCreateTableColumnTypeComments() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractPlatformTestCase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractPlatformTestCase, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Doctrine\DBAL\Tests\Platforms;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\DBAL\DBALException;
7
use Doctrine\DBAL\Events;
8
use Doctrine\DBAL\Platforms\AbstractPlatform;
9
use Doctrine\DBAL\Platforms\Keywords\KeywordList;
10
use Doctrine\DBAL\Schema\Column;
11
use Doctrine\DBAL\Schema\ColumnDiff;
12
use Doctrine\DBAL\Schema\Comparator;
13
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
14
use Doctrine\DBAL\Schema\Index;
15
use Doctrine\DBAL\Schema\Table;
16
use Doctrine\DBAL\Schema\TableDiff;
17
use Doctrine\DBAL\Schema\UniqueConstraint;
18
use Doctrine\DBAL\Types\Type;
19
use PHPUnit\Framework\TestCase;
20
use function get_class;
21
use function implode;
22
use function sprintf;
23
use function str_repeat;
24
25
abstract class AbstractPlatformTestCase extends TestCase
26
{
27
    /** @var AbstractPlatform */
28
    protected $platform;
29
30
    abstract public function createPlatform() : AbstractPlatform;
31
32
    protected function setUp() : void
33
    {
34
        $this->platform = $this->createPlatform();
35
    }
36
37
    /**
38
     * @group DDC-1360
39
     */
40
    public function testQuoteIdentifier() : void
41
    {
42
        if ($this->platform->getName() === 'mssql') {
43
            self::markTestSkipped('Not working this way on mssql.');
44
        }
45
46
        $c = $this->platform->getIdentifierQuoteCharacter();
47
        self::assertEquals($c . 'test' . $c, $this->platform->quoteIdentifier('test'));
48
        self::assertEquals($c . 'test' . $c . '.' . $c . 'test' . $c, $this->platform->quoteIdentifier('test.test'));
49
        self::assertEquals(str_repeat($c, 4), $this->platform->quoteIdentifier($c));
50
    }
51
52
    /**
53
     * @group DDC-1360
54
     */
55
    public function testQuoteSingleIdentifier() : void
56
    {
57
        if ($this->platform->getName() === 'mssql') {
58
            self::markTestSkipped('Not working this way on mssql.');
59
        }
60
61
        $c = $this->platform->getIdentifierQuoteCharacter();
62
        self::assertEquals($c . 'test' . $c, $this->platform->quoteSingleIdentifier('test'));
63
        self::assertEquals($c . 'test.test' . $c, $this->platform->quoteSingleIdentifier('test.test'));
64
        self::assertEquals(str_repeat($c, 4), $this->platform->quoteSingleIdentifier($c));
65
    }
66
67
    /**
68
     * @group DBAL-1029
69
     * @dataProvider getReturnsForeignKeyReferentialActionSQL
70
     */
71
    public function testReturnsForeignKeyReferentialActionSQL(string $action, string $expectedSQL) : void
72
    {
73
        self::assertSame($expectedSQL, $this->platform->getForeignKeyReferentialActionSQL($action));
74
    }
75
76
    /**
77
     * @return mixed[][]
78
     */
79
    public static function getReturnsForeignKeyReferentialActionSQL() : iterable
80
    {
81
        return [
82
            ['CASCADE', 'CASCADE'],
83
            ['SET NULL', 'SET NULL'],
84
            ['NO ACTION', 'NO ACTION'],
85
            ['RESTRICT', 'RESTRICT'],
86
            ['SET DEFAULT', 'SET DEFAULT'],
87
            ['CaScAdE', 'CASCADE'],
88
        ];
89
    }
90
91
    public function testGetInvalidForeignKeyReferentialActionSQL() : void
92
    {
93
        $this->expectException('InvalidArgumentException');
94
        $this->platform->getForeignKeyReferentialActionSQL('unknown');
95
    }
96
97
    public function testGetUnknownDoctrineMappingType() : void
98
    {
99
        $this->expectException(DBALException::class);
100
        $this->platform->getDoctrineTypeMapping('foobar');
101
    }
102
103
    public function testRegisterDoctrineMappingType() : void
104
    {
105
        $this->platform->registerDoctrineTypeMapping('foo', 'integer');
106
        self::assertEquals('integer', $this->platform->getDoctrineTypeMapping('foo'));
107
    }
108
109
    public function testRegisterUnknownDoctrineMappingType() : void
110
    {
111
        $this->expectException(DBALException::class);
112
        $this->platform->registerDoctrineTypeMapping('foo', 'bar');
113
    }
114
115
    /**
116
     * @group DBAL-2594
117
     */
118
    public function testRegistersCommentedDoctrineMappingTypeImplicitly() : void
119
    {
120
        $type = Type::getType('array');
121
        $this->platform->registerDoctrineTypeMapping('foo', 'array');
122
123
        self::assertTrue($this->platform->isCommentedDoctrineType($type));
124
    }
125
126
    /**
127
     * @group DBAL-939
128
     * @dataProvider getIsCommentedDoctrineType
129
     */
130
    public function testIsCommentedDoctrineType(Type $type, bool $commented) : void
131
    {
132
        self::assertSame($commented, $this->platform->isCommentedDoctrineType($type));
133
    }
134
135
    /**
136
     * @return mixed[]
137
     */
138
    public function getIsCommentedDoctrineType() : iterable
139
    {
140
        $this->setUp();
141
142
        $data = [];
143
144
        foreach (Type::getTypesMap() as $typeName => $className) {
145
            $type = Type::getType($typeName);
146
147
            $data[$typeName] = [
148
                $type,
149
                $type->requiresSQLCommentHint($this->platform),
150
            ];
151
        }
152
153
        return $data;
154
    }
155
156
    public function testCreateWithNoColumns() : void
157
    {
158
        $table = new Table('test');
159
160
        $this->expectException(DBALException::class);
161
        $sql = $this->platform->getCreateTableSQL($table);
0 ignored issues
show
Unused Code introduced by
The assignment to $sql is dead and can be removed.
Loading history...
162
    }
163
164
    public function testGeneratesTableCreationSql() : void
165
    {
166
        $table = new Table('test');
167
        $table->addColumn('id', 'integer', ['notnull' => true, 'autoincrement' => true]);
168
        $table->addColumn('test', 'string', ['notnull' => false, 'length' => 255]);
169
        $table->setPrimaryKey(['id']);
170
171
        $sql = $this->platform->getCreateTableSQL($table);
172
        self::assertEquals($this->getGenerateTableSql(), $sql[0]);
173
    }
174
175
    abstract public function getGenerateTableSql() : string;
176
177
    public function testGenerateTableWithMultiColumnUniqueIndex() : void
178
    {
179
        $table = new Table('test');
180
        $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]);
181
        $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]);
182
        $table->addUniqueIndex(['foo', 'bar']);
183
184
        $sql = $this->platform->getCreateTableSQL($table);
185
        self::assertEquals($this->getGenerateTableWithMultiColumnUniqueIndexSql(), $sql);
186
    }
187
188
    /**
189
     * @return string[]
190
     */
191
    abstract public function getGenerateTableWithMultiColumnUniqueIndexSql() : array;
192
193
    public function testGeneratesIndexCreationSql() : void
194
    {
195
        $indexDef = new Index('my_idx', ['user_name', 'last_login']);
196
197
        self::assertEquals(
198
            $this->getGenerateIndexSql(),
199
            $this->platform->getCreateIndexSQL($indexDef, 'mytable')
200
        );
201
    }
202
203
    abstract public function getGenerateIndexSql() : string;
204
205
    public function testGeneratesUniqueIndexCreationSql() : void
206
    {
207
        $indexDef = new Index('index_name', ['test', 'test2'], true);
208
209
        $sql = $this->platform->getCreateIndexSQL($indexDef, 'test');
210
        self::assertEquals($this->getGenerateUniqueIndexSql(), $sql);
211
    }
212
213
    abstract public function getGenerateUniqueIndexSql() : string;
214
215
    public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() : void
216
    {
217
        $where            = 'test IS NULL AND test2 IS NOT NULL';
218
        $indexDef         = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]);
219
        $uniqueConstraint = new UniqueConstraint('name', ['test', 'test2'], [], []);
220
221
        $expected = ' WHERE ' . $where;
222
223
        $actuals = [];
224
225
        if ($this->supportsInlineIndexDeclaration()) {
226
            $actuals[] = $this->platform->getIndexDeclarationSQL('name', $indexDef);
227
        }
228
229
        $uniqueConstraintSQL = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueConstraint);
230
        $indexSQL            = $this->platform->getCreateIndexSQL($indexDef, 'table');
231
232
        $this->assertStringEndsNotWith($expected, $uniqueConstraintSQL, 'WHERE clause should NOT be present');
233
234
        foreach ($actuals as $actual) {
235
            if ($this->platform->supportsPartialIndexes()) {
236
                self::assertStringEndsWith($expected, $indexSQL, 'WHERE clause should be present');
237
            } else {
238
                self::assertStringEndsNotWith($expected, $indexSQL, 'WHERE clause should NOT be present');
239
            }
240
        }
241
    }
242
243
    public function testGeneratesForeignKeyCreationSql() : void
244
    {
245
        $fk = new ForeignKeyConstraint(['fk_name_id'], 'other_table', ['id'], '');
246
247
        $sql = $this->platform->getCreateForeignKeySQL($fk, 'test');
248
        self::assertEquals($sql, $this->getGenerateForeignKeySql());
249
    }
250
251
    abstract public function getGenerateForeignKeySql() : string;
252
253
    public function testGeneratesConstraintCreationSql() : void
254
    {
255
        if (! $this->platform->supportsCreateDropForeignKeyConstraints()) {
256
            $this->markTestSkipped('Platform does not support creating or dropping foreign key constraints.');
257
        }
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
    protected function getBitAndComparisonExpressionSql(string $value1, string $value2) : string
273
    {
274
        return '(' . $value1 . ' & ' . $value2 . ')';
275
    }
276
277
    /**
278
     * @group DDC-1213
279
     */
280
    public function testGeneratesBitAndComparisonExpressionSql() : void
281
    {
282
        $sql = $this->platform->getBitAndComparisonExpression(2, 4);
283
        self::assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql);
284
    }
285
286
    protected function getBitOrComparisonExpressionSql(string $value1, string $value2) : string
287
    {
288
        return '(' . $value1 . ' | ' . $value2 . ')';
289
    }
290
291
    /**
292
     * @group DDC-1213
293
     */
294
    public function testGeneratesBitOrComparisonExpressionSql() : void
295
    {
296
        $sql = $this->platform->getBitOrComparisonExpression(2, 4);
297
        self::assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql);
298
    }
299
300
    public function getGenerateConstraintUniqueIndexSql() : string
301
    {
302
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)';
303
    }
304
305
    public function getGenerateConstraintPrimaryIndexSql() : string
306
    {
307
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)';
308
    }
309
310
    public function getGenerateConstraintForeignKeySql(ForeignKeyConstraint $fk) : string
311
    {
312
        $quotedForeignTable = $fk->getQuotedForeignTableName($this->platform);
313
314
        return sprintf(
315
            'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES %s (id)',
316
            $quotedForeignTable
317
        );
318
    }
319
320
    /**
321
     * @return string[]
322
     */
323
    abstract public function getGenerateAlterTableSql() : array;
324
325
    public function testGeneratesTableAlterationSql() : void
326
    {
327
        $expectedSql = $this->getGenerateAlterTableSql();
328
329
        $table = new Table('mytable');
330
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
331
        $table->addColumn('foo', 'integer');
332
        $table->addColumn('bar', 'string');
333
        $table->addColumn('bloo', 'boolean');
334
        $table->setPrimaryKey(['id']);
335
336
        $tableDiff                         = new TableDiff('mytable');
337
        $tableDiff->fromTable              = $table;
338
        $tableDiff->newName                = 'userlist';
339
        $tableDiff->addedColumns['quota']  = new Column('quota', Type::getType('integer'), ['notnull' => false]);
340
        $tableDiff->removedColumns['foo']  = new Column('foo', Type::getType('integer'));
341
        $tableDiff->changedColumns['bar']  = new ColumnDiff(
342
            'bar',
343
            new Column(
344
                'baz',
345
                Type::getType('string'),
346
                ['default' => 'def']
347
            ),
348
            ['type', 'notnull', 'default']
349
        );
350
        $tableDiff->changedColumns['bloo'] = new ColumnDiff(
351
            'bloo',
352
            new Column(
353
                'bloo',
354
                Type::getType('boolean'),
355
                ['default' => false]
356
            ),
357
            ['type', 'notnull', 'default']
358
        );
359
360
        $sql = $this->platform->getAlterTableSQL($tableDiff);
361
362
        self::assertEquals($expectedSql, $sql);
363
    }
364
365
    public function testGetCustomColumnDeclarationSql() : void
366
    {
367
        $field = ['columnDefinition' => 'MEDIUMINT(6) UNSIGNED'];
368
        self::assertEquals('foo MEDIUMINT(6) UNSIGNED', $this->platform->getColumnDeclarationSQL('foo', $field));
369
    }
370
371
    public function testGetCreateTableSqlDispatchEvent() : void
372
    {
373
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetCreateTableSqlDispatchEvenListener'))
374
            ->addMethods(['onSchemaCreateTable', 'onSchemaCreateTableColumn'])
375
            ->getMock();
376
        $listenerMock
377
            ->expects(self::once())
378
            ->method('onSchemaCreateTable');
379
        $listenerMock
380
            ->expects(self::exactly(2))
381
            ->method('onSchemaCreateTableColumn');
382
383
        $eventManager = new EventManager();
384
        $eventManager->addEventListener([Events::onSchemaCreateTable, Events::onSchemaCreateTableColumn], $listenerMock);
385
386
        $this->platform->setEventManager($eventManager);
387
388
        $table = new Table('test');
389
        $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]);
390
        $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]);
391
392
        $this->platform->getCreateTableSQL($table);
393
    }
394
395
    public function testGetDropTableSqlDispatchEvent() : void
396
    {
397
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetDropTableSqlDispatchEventListener'))
398
            ->addMethods(['onSchemaDropTable'])
399
            ->getMock();
400
        $listenerMock
401
            ->expects(self::once())
402
            ->method('onSchemaDropTable');
403
404
        $eventManager = new EventManager();
405
        $eventManager->addEventListener([Events::onSchemaDropTable], $listenerMock);
406
407
        $this->platform->setEventManager($eventManager);
408
409
        $this->platform->getDropTableSQL('TABLE');
410
    }
411
412
    public function testGetAlterTableSqlDispatchEvent() : void
413
    {
414
        $events = [
415
            'onSchemaAlterTable',
416
            'onSchemaAlterTableAddColumn',
417
            'onSchemaAlterTableRemoveColumn',
418
            'onSchemaAlterTableChangeColumn',
419
            'onSchemaAlterTableRenameColumn',
420
        ];
421
422
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetAlterTableSqlDispatchEvenListener'))
423
            ->addMethods($events)
424
            ->getMock();
425
        $listenerMock
426
            ->expects(self::once())
427
            ->method('onSchemaAlterTable');
428
        $listenerMock
429
            ->expects(self::once())
430
            ->method('onSchemaAlterTableAddColumn');
431
        $listenerMock
432
            ->expects(self::once())
433
            ->method('onSchemaAlterTableRemoveColumn');
434
        $listenerMock
435
            ->expects(self::once())
436
            ->method('onSchemaAlterTableChangeColumn');
437
        $listenerMock
438
            ->expects(self::once())
439
            ->method('onSchemaAlterTableRenameColumn');
440
441
        $eventManager = new EventManager();
442
        $events       = [
443
            Events::onSchemaAlterTable,
444
            Events::onSchemaAlterTableAddColumn,
445
            Events::onSchemaAlterTableRemoveColumn,
446
            Events::onSchemaAlterTableChangeColumn,
447
            Events::onSchemaAlterTableRenameColumn,
448
        ];
449
        $eventManager->addEventListener($events, $listenerMock);
450
451
        $this->platform->setEventManager($eventManager);
452
453
        $table = new Table('mytable');
454
        $table->addColumn('removed', 'integer');
455
        $table->addColumn('changed', 'integer');
456
        $table->addColumn('renamed', 'integer');
457
458
        $tableDiff                            = new TableDiff('mytable');
459
        $tableDiff->fromTable                 = $table;
460
        $tableDiff->addedColumns['added']     = new Column('added', Type::getType('integer'), []);
461
        $tableDiff->removedColumns['removed'] = new Column('removed', Type::getType('integer'), []);
462
        $tableDiff->changedColumns['changed'] = new ColumnDiff(
463
            'changed',
464
            new Column(
465
                'changed2',
466
                Type::getType('string'),
467
                []
468
            ),
469
            []
470
        );
471
        $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer'), []);
472
473
        $this->platform->getAlterTableSQL($tableDiff);
474
    }
475
476
    /**
477
     * @group DBAL-42
478
     */
479
    public function testCreateTableColumnComments() : void
480
    {
481
        $table = new Table('test');
482
        $table->addColumn('id', 'integer', ['comment' => 'This is a comment']);
483
        $table->setPrimaryKey(['id']);
484
485
        self::assertEquals($this->getCreateTableColumnCommentsSQL(), $this->platform->getCreateTableSQL($table));
486
    }
487
488
    /**
489
     * @group DBAL-42
490
     */
491
    public function testAlterTableColumnComments() : void
492
    {
493
        $tableDiff                        = new TableDiff('mytable');
494
        $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']);
495
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
496
            'foo',
497
            new Column(
498
                'foo',
499
                Type::getType('string')
500
            ),
501
            ['comment']
502
        );
503
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
504
            'bar',
505
            new Column(
506
                'baz',
507
                Type::getType('string'),
508
                ['comment' => 'B comment']
509
            ),
510
            ['comment']
511
        );
512
513
        self::assertEquals($this->getAlterTableColumnCommentsSQL(), $this->platform->getAlterTableSQL($tableDiff));
514
    }
515
516
    public function testCreateTableColumnTypeComments() : void
517
    {
518
        $table = new Table('test');
519
        $table->addColumn('id', 'integer');
520
        $table->addColumn('data', 'array');
521
        $table->setPrimaryKey(['id']);
522
523
        self::assertEquals($this->getCreateTableColumnTypeCommentsSQL(), $this->platform->getCreateTableSQL($table));
524
    }
525
526
    /**
527
     * @return string[]
528
     */
529
    public function getCreateTableColumnCommentsSQL() : array
530
    {
531
        self::markTestSkipped('Platform does not support Column comments.');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
532
    }
533
534
    /**
535
     * @return string[]
536
     */
537
    public function getAlterTableColumnCommentsSQL() : array
538
    {
539
        self::markTestSkipped('Platform does not support Column comments.');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
540
    }
541
542
    /**
543
     * @return string[]
544
     */
545
    public function getCreateTableColumnTypeCommentsSQL() : array
546
    {
547
        self::markTestSkipped('Platform does not support Column comments.');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
548
    }
549
550
    public function testGetDefaultValueDeclarationSQL() : void
551
    {
552
        // non-timestamp value will get single quotes
553
        $field = [
554
            'type' => Type::getType('string'),
555
            'default' => 'non_timestamp',
556
        ];
557
558
        self::assertEquals(" DEFAULT 'non_timestamp'", $this->platform->getDefaultValueDeclarationSQL($field));
559
    }
560
561
    /**
562
     * @group 2859
563
     */
564
    public function testGetDefaultValueDeclarationSQLDateTime() : void
565
    {
566
        // timestamps on datetime types should not be quoted
567
        foreach (['datetime', 'datetimetz', 'datetime_immutable', 'datetimetz_immutable'] as $type) {
568
            $field = [
569
                'type'    => Type::getType($type),
570
                'default' => $this->platform->getCurrentTimestampSQL(),
571
            ];
572
573
            self::assertSame(
574
                ' DEFAULT ' . $this->platform->getCurrentTimestampSQL(),
575
                $this->platform->getDefaultValueDeclarationSQL($field)
576
            );
577
        }
578
    }
579
580
    public function testGetDefaultValueDeclarationSQLForIntegerTypes() : void
581
    {
582
        foreach (['bigint', 'integer', 'smallint'] as $type) {
583
            $field = [
584
                'type'    => Type::getType($type),
585
                'default' => 1,
586
            ];
587
588
            self::assertEquals(
589
                ' DEFAULT 1',
590
                $this->platform->getDefaultValueDeclarationSQL($field)
591
            );
592
        }
593
    }
594
595
    /**
596
     * @group 2859
597
     */
598
    public function testGetDefaultValueDeclarationSQLForDateType() : void
599
    {
600
        $currentDateSql = $this->platform->getCurrentDateSQL();
601
        foreach (['date', 'date_immutable'] as $type) {
602
            $field = [
603
                'type'    => Type::getType($type),
604
                'default' => $currentDateSql,
605
            ];
606
607
            self::assertSame(
608
                ' DEFAULT ' . $currentDateSql,
609
                $this->platform->getDefaultValueDeclarationSQL($field)
610
            );
611
        }
612
    }
613
614
    /**
615
     * @group DBAL-45
616
     */
617
    public function testKeywordList() : void
618
    {
619
        $keywordList = $this->platform->getReservedKeywordsList();
620
        self::assertInstanceOf(KeywordList::class, $keywordList);
621
622
        self::assertTrue($keywordList->isKeyword('table'));
623
    }
624
625
    /**
626
     * @group DBAL-374
627
     */
628
    public function testQuotedColumnInPrimaryKeyPropagation() : void
629
    {
630
        $table = new Table('`quoted`');
631
        $table->addColumn('create', 'string');
632
        $table->setPrimaryKey(['create']);
633
634
        $sql = $this->platform->getCreateTableSQL($table);
635
        self::assertEquals($this->getQuotedColumnInPrimaryKeySQL(), $sql);
636
    }
637
638
    /**
639
     * @return string[]
640
     */
641
    abstract protected function getQuotedColumnInPrimaryKeySQL() : array;
642
643
    /**
644
     * @return string[]
645
     */
646
    abstract protected function getQuotedColumnInIndexSQL() : array;
647
648
    /**
649
     * @return string[]
650
     */
651
    abstract protected function getQuotedNameInIndexSQL() : array;
652
653
    /**
654
     * @return string[]
655
     */
656
    abstract protected function getQuotedColumnInForeignKeySQL() : array;
657
658
    /**
659
     * @group DBAL-374
660
     */
661
    public function testQuotedColumnInIndexPropagation() : void
662
    {
663
        $table = new Table('`quoted`');
664
        $table->addColumn('create', 'string');
665
        $table->addIndex(['create']);
666
667
        $sql = $this->platform->getCreateTableSQL($table);
668
        self::assertEquals($this->getQuotedColumnInIndexSQL(), $sql);
669
    }
670
671
    public function testQuotedNameInIndexSQL() : void
672
    {
673
        $table = new Table('test');
674
        $table->addColumn('column1', 'string');
675
        $table->addIndex(['column1'], '`key`');
676
677
        $sql = $this->platform->getCreateTableSQL($table);
678
        self::assertEquals($this->getQuotedNameInIndexSQL(), $sql);
679
    }
680
681
    /**
682
     * @group DBAL-374
683
     */
684
    public function testQuotedColumnInForeignKeyPropagation() : void
685
    {
686
        $table = new Table('`quoted`');
687
        $table->addColumn('create', 'string');
688
        $table->addColumn('foo', 'string');
689
        $table->addColumn('`bar`', 'string');
690
691
        // Foreign table with reserved keyword as name (needs quotation).
692
        $foreignTable = new Table('foreign');
693
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
694
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
695
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
696
697
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_RESERVED_KEYWORD');
698
699
        // Foreign table with non-reserved keyword as name (does not need quotation).
700
        $foreignTable = new Table('foo');
701
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
702
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
703
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
704
705
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_NON_RESERVED_KEYWORD');
706
707
        // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
708
        $foreignTable = new Table('`foo-bar`');
709
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
710
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
711
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
712
713
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_INTENDED_QUOTATION');
714
715
        $sql = $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS);
716
        self::assertEquals($this->getQuotedColumnInForeignKeySQL(), $sql);
717
    }
718
719
    /**
720
     * @group DBAL-1051
721
     */
722
    public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : void
723
    {
724
        $constraint = new UniqueConstraint('select', ['foo'], [], []);
725
726
        self::assertSame(
727
            $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(),
728
            $this->platform->getUniqueConstraintDeclarationSQL('select', $constraint)
729
        );
730
    }
731
732
    abstract protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string;
733
734
    /**
735
     * @group DBAL-2270
736
     */
737
    public function testQuotesReservedKeywordInTruncateTableSQL() : void
738
    {
739
        self::assertSame(
740
            $this->getQuotesReservedKeywordInTruncateTableSQL(),
741
            $this->platform->getTruncateTableSQL('select')
742
        );
743
    }
744
745
    abstract protected function getQuotesReservedKeywordInTruncateTableSQL() : string;
746
747
    /**
748
     * @group DBAL-1051
749
     */
750
    public function testQuotesReservedKeywordInIndexDeclarationSQL() : void
751
    {
752
        $index = new Index('select', ['foo']);
753
754
        if (! $this->supportsInlineIndexDeclaration()) {
755
            $this->expectException(DBALException::class);
756
        }
757
758
        self::assertSame(
759
            $this->getQuotesReservedKeywordInIndexDeclarationSQL(),
760
            $this->platform->getIndexDeclarationSQL('select', $index)
761
        );
762
    }
763
764
    abstract protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string;
765
766
    protected function supportsInlineIndexDeclaration() : bool
767
    {
768
        return true;
769
    }
770
771
    public function testSupportsCommentOnStatement() : void
772
    {
773
        self::assertSame($this->supportsCommentOnStatement(), $this->platform->supportsCommentOnStatement());
774
    }
775
776
    protected function supportsCommentOnStatement() : bool
777
    {
778
        return false;
779
    }
780
781
    public function testGetCreateSchemaSQL() : void
782
    {
783
        $this->expectException(DBALException::class);
784
785
        $this->platform->getCreateSchemaSQL('schema');
786
    }
787
788
    /**
789
     * @group DBAL-585
790
     */
791
    public function testAlterTableChangeQuotedColumn() : void
792
    {
793
        $tableDiff                        = new TableDiff('mytable');
794
        $tableDiff->fromTable             = new Table('mytable');
795
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
796
            'select',
797
            new Column(
798
                'select',
799
                Type::getType('string')
800
            ),
801
            ['type']
802
        );
803
804
        self::assertStringContainsString(
805
            $this->platform->quoteIdentifier('select'),
806
            implode(';', $this->platform->getAlterTableSQL($tableDiff))
807
        );
808
    }
809
810
    /**
811
     * @group DBAL-563
812
     */
813
    public function testUsesSequenceEmulatedIdentityColumns() : void
814
    {
815
        self::assertFalse($this->platform->usesSequenceEmulatedIdentityColumns());
816
    }
817
818
    public function testGetSequencePrefixWithoutSchema() : void
819
    {
820
        self::assertEquals('foo', $this->platform->getSequencePrefix('foo'));
821
    }
822
823
    public function testGetSequencePrefixWithSchema() : void
824
    {
825
        self::assertEquals('bar.foo', $this->platform->getSequencePrefix('foo', 'bar'));
826
    }
827
828
    /**
829
     * @group DBAL-563
830
     */
831
    public function testReturnsIdentitySequenceName() : void
832
    {
833
        $this->expectException(DBALException::class);
834
835
        $this->platform->getIdentitySequenceName('mytable', 'mycolumn');
836
    }
837
838
    public function testReturnsBinaryDefaultLength() : void
839
    {
840
        self::assertSame($this->getBinaryDefaultLength(), $this->platform->getBinaryDefaultLength());
841
    }
842
843
    protected function getBinaryDefaultLength() : int
844
    {
845
        return 255;
846
    }
847
848
    public function testReturnsBinaryMaxLength() : void
849
    {
850
        self::assertSame($this->getBinaryMaxLength(), $this->platform->getBinaryMaxLength());
851
    }
852
853
    protected function getBinaryMaxLength() : int
854
    {
855
        return 4000;
856
    }
857
858
    public function testReturnsBinaryTypeDeclarationSQL() : void
859
    {
860
        $this->expectException(DBALException::class);
861
862
        $this->platform->getBinaryTypeDeclarationSQL([]);
863
    }
864
865
    public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void
866
    {
867
        $this->markTestSkipped('Not applicable to the platform');
868
    }
869
870
    /**
871
     * @group DBAL-553
872
     */
873
    public function hasNativeJsonType() : void
874
    {
875
        self::assertFalse($this->platform->hasNativeJsonType());
876
    }
877
878
    /**
879
     * @group DBAL-553
880
     */
881
    public function testReturnsJsonTypeDeclarationSQL() : void
882
    {
883
        $column = [
884
            'length'  => 666,
885
            'notnull' => true,
886
            'type'    => Type::getType('json_array'),
887
        ];
888
889
        self::assertSame(
890
            $this->platform->getClobTypeDeclarationSQL($column),
891
            $this->platform->getJsonTypeDeclarationSQL($column)
892
        );
893
    }
894
895
    /**
896
     * @group DBAL-234
897
     */
898
    public function testAlterTableRenameIndex() : void
899
    {
900
        $tableDiff            = new TableDiff('mytable');
901
        $tableDiff->fromTable = new Table('mytable');
902
        $tableDiff->fromTable->addColumn('id', 'integer');
903
        $tableDiff->fromTable->setPrimaryKey(['id']);
904
        $tableDiff->renamedIndexes = [
905
            'idx_foo' => new Index('idx_bar', ['id']),
906
        ];
907
908
        self::assertSame(
909
            $this->getAlterTableRenameIndexSQL(),
910
            $this->platform->getAlterTableSQL($tableDiff)
911
        );
912
    }
913
914
    /**
915
     * @return string[]
916
     *
917
     * @group DBAL-234
918
     */
919
    protected function getAlterTableRenameIndexSQL() : array
920
    {
921
        return [
922
            'DROP INDEX idx_foo',
923
            'CREATE INDEX idx_bar ON mytable (id)',
924
        ];
925
    }
926
927
    /**
928
     * @group DBAL-234
929
     */
930
    public function testQuotesAlterTableRenameIndex() : void
931
    {
932
        $tableDiff            = new TableDiff('table');
933
        $tableDiff->fromTable = new Table('table');
934
        $tableDiff->fromTable->addColumn('id', 'integer');
935
        $tableDiff->fromTable->setPrimaryKey(['id']);
936
        $tableDiff->renamedIndexes = [
937
            'create' => new Index('select', ['id']),
938
            '`foo`'  => new Index('`bar`', ['id']),
939
        ];
940
941
        self::assertSame(
942
            $this->getQuotedAlterTableRenameIndexSQL(),
943
            $this->platform->getAlterTableSQL($tableDiff)
944
        );
945
    }
946
947
    /**
948
     * @return string[]
949
     *
950
     * @group DBAL-234
951
     */
952
    protected function getQuotedAlterTableRenameIndexSQL() : array
953
    {
954
        return [
955
            'DROP INDEX "create"',
956
            'CREATE INDEX "select" ON "table" (id)',
957
            'DROP INDEX "foo"',
958
            'CREATE INDEX "bar" ON "table" (id)',
959
        ];
960
    }
961
962
    /**
963
     * @group DBAL-835
964
     */
965
    public function testQuotesAlterTableRenameColumn() : void
966
    {
967
        $fromTable = new Table('mytable');
968
969
        $fromTable->addColumn('unquoted1', 'integer', ['comment' => 'Unquoted 1']);
970
        $fromTable->addColumn('unquoted2', 'integer', ['comment' => 'Unquoted 2']);
971
        $fromTable->addColumn('unquoted3', 'integer', ['comment' => 'Unquoted 3']);
972
973
        $fromTable->addColumn('create', 'integer', ['comment' => 'Reserved keyword 1']);
974
        $fromTable->addColumn('table', 'integer', ['comment' => 'Reserved keyword 2']);
975
        $fromTable->addColumn('select', 'integer', ['comment' => 'Reserved keyword 3']);
976
977
        $fromTable->addColumn('`quoted1`', 'integer', ['comment' => 'Quoted 1']);
978
        $fromTable->addColumn('`quoted2`', 'integer', ['comment' => 'Quoted 2']);
979
        $fromTable->addColumn('`quoted3`', 'integer', ['comment' => 'Quoted 3']);
980
981
        $toTable = new Table('mytable');
982
983
        $toTable->addColumn('unquoted', 'integer', ['comment' => 'Unquoted 1']); // unquoted -> unquoted
984
        $toTable->addColumn('where', 'integer', ['comment' => 'Unquoted 2']); // unquoted -> reserved keyword
985
        $toTable->addColumn('`foo`', 'integer', ['comment' => 'Unquoted 3']); // unquoted -> quoted
986
987
        $toTable->addColumn('reserved_keyword', 'integer', ['comment' => 'Reserved keyword 1']); // reserved keyword -> unquoted
988
        $toTable->addColumn('from', 'integer', ['comment' => 'Reserved keyword 2']); // reserved keyword -> reserved keyword
989
        $toTable->addColumn('`bar`', 'integer', ['comment' => 'Reserved keyword 3']); // reserved keyword -> quoted
990
991
        $toTable->addColumn('quoted', 'integer', ['comment' => 'Quoted 1']); // quoted -> unquoted
992
        $toTable->addColumn('and', 'integer', ['comment' => 'Quoted 2']); // quoted -> reserved keyword
993
        $toTable->addColumn('`baz`', 'integer', ['comment' => 'Quoted 3']); // quoted -> quoted
994
995
        $comparator = new Comparator();
996
997
        self::assertEquals(
998
            $this->getQuotedAlterTableRenameColumnSQL(),
999
            $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable))
0 ignored issues
show
Bug introduced by
It seems like $comparator->diffTable($fromTable, $toTable) can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

999
            $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $comparator->diffTable($fromTable, $toTable))
Loading history...
1000
        );
1001
    }
1002
1003
    /**
1004
     * Returns SQL statements for {@link testQuotesAlterTableRenameColumn}.
1005
     *
1006
     * @return string[]
1007
     *
1008
     * @group DBAL-835
1009
     */
1010
    abstract protected function getQuotedAlterTableRenameColumnSQL() : array;
1011
1012
    /**
1013
     * @group DBAL-835
1014
     */
1015
    public function testQuotesAlterTableChangeColumnLength() : void
1016
    {
1017
        $fromTable = new Table('mytable');
1018
1019
        $fromTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 10]);
1020
        $fromTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 10]);
1021
        $fromTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 10]);
1022
1023
        $fromTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 10]);
1024
        $fromTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 10]);
1025
        $fromTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 10]);
1026
1027
        $toTable = new Table('mytable');
1028
1029
        $toTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 255]);
1030
        $toTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 255]);
1031
        $toTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 255]);
1032
1033
        $toTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 255]);
1034
        $toTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 255]);
1035
        $toTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 255]);
1036
1037
        $comparator = new Comparator();
1038
1039
        self::assertEquals(
1040
            $this->getQuotedAlterTableChangeColumnLengthSQL(),
1041
            $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable))
0 ignored issues
show
Bug introduced by
It seems like $comparator->diffTable($fromTable, $toTable) can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

1041
            $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $comparator->diffTable($fromTable, $toTable))
Loading history...
1042
        );
1043
    }
1044
1045
    /**
1046
     * Returns SQL statements for {@link testQuotesAlterTableChangeColumnLength}.
1047
     *
1048
     * @return string[]
1049
     *
1050
     * @group DBAL-835
1051
     */
1052
    abstract protected function getQuotedAlterTableChangeColumnLengthSQL() : array;
1053
1054
    /**
1055
     * @group DBAL-807
1056
     */
1057
    public function testAlterTableRenameIndexInSchema() : void
1058
    {
1059
        $tableDiff            = new TableDiff('myschema.mytable');
1060
        $tableDiff->fromTable = new Table('myschema.mytable');
1061
        $tableDiff->fromTable->addColumn('id', 'integer');
1062
        $tableDiff->fromTable->setPrimaryKey(['id']);
1063
        $tableDiff->renamedIndexes = [
1064
            'idx_foo' => new Index('idx_bar', ['id']),
1065
        ];
1066
1067
        self::assertSame(
1068
            $this->getAlterTableRenameIndexInSchemaSQL(),
1069
            $this->platform->getAlterTableSQL($tableDiff)
1070
        );
1071
    }
1072
1073
    /**
1074
     * @return string[]
1075
     *
1076
     * @group DBAL-807
1077
     */
1078
    protected function getAlterTableRenameIndexInSchemaSQL() : array
1079
    {
1080
        return [
1081
            'DROP INDEX idx_foo',
1082
            'CREATE INDEX idx_bar ON myschema.mytable (id)',
1083
        ];
1084
    }
1085
1086
    /**
1087
     * @group DBAL-807
1088
     */
1089
    public function testQuotesAlterTableRenameIndexInSchema() : void
1090
    {
1091
        $tableDiff            = new TableDiff('`schema`.table');
1092
        $tableDiff->fromTable = new Table('`schema`.table');
1093
        $tableDiff->fromTable->addColumn('id', 'integer');
1094
        $tableDiff->fromTable->setPrimaryKey(['id']);
1095
        $tableDiff->renamedIndexes = [
1096
            'create' => new Index('select', ['id']),
1097
            '`foo`'  => new Index('`bar`', ['id']),
1098
        ];
1099
1100
        self::assertSame(
1101
            $this->getQuotedAlterTableRenameIndexInSchemaSQL(),
1102
            $this->platform->getAlterTableSQL($tableDiff)
1103
        );
1104
    }
1105
1106
    /**
1107
     * @return string[]
1108
     *
1109
     * @group DBAL-234
1110
     */
1111
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
1112
    {
1113
        return [
1114
            'DROP INDEX "schema"."create"',
1115
            'CREATE INDEX "select" ON "schema"."table" (id)',
1116
            'DROP INDEX "schema"."foo"',
1117
            'CREATE INDEX "bar" ON "schema"."table" (id)',
1118
        ];
1119
    }
1120
1121
    /**
1122
     * @group DBAL-1237
1123
     */
1124
    public function testQuotesDropForeignKeySQL() : void
1125
    {
1126
        if (! $this->platform->supportsCreateDropForeignKeyConstraints()) {
1127
            self::markTestSkipped(
1128
                sprintf('%s does not support modifying foreign key constraints.', get_class($this->platform))
1129
            );
1130
        }
1131
1132
        $tableName      = 'table';
1133
        $table          = new Table($tableName);
1134
        $foreignKeyName = 'select';
1135
        $foreignKey     = new ForeignKeyConstraint([], 'foo', [], 'select');
1136
        $expectedSql    = $this->getQuotesDropForeignKeySQL();
1137
1138
        self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKeyName, $tableName));
1139
        self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKey, $table));
1140
    }
1141
1142
    protected function getQuotesDropForeignKeySQL() : string
1143
    {
1144
        return 'ALTER TABLE "table" DROP FOREIGN KEY "select"';
1145
    }
1146
1147
    /**
1148
     * @group DBAL-1237
1149
     */
1150
    public function testQuotesDropConstraintSQL() : void
1151
    {
1152
        $tableName      = 'table';
1153
        $table          = new Table($tableName);
1154
        $constraintName = 'select';
1155
        $constraint     = new ForeignKeyConstraint([], 'foo', [], 'select');
1156
        $expectedSql    = $this->getQuotesDropConstraintSQL();
1157
1158
        self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraintName, $tableName));
1159
        self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraint, $table));
1160
    }
1161
1162
    protected function getQuotesDropConstraintSQL() : string
1163
    {
1164
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
1165
    }
1166
1167
    protected function getStringLiteralQuoteCharacter() : string
1168
    {
1169
        return "'";
1170
    }
1171
1172
    public function testGetStringLiteralQuoteCharacter() : void
1173
    {
1174
        self::assertSame($this->getStringLiteralQuoteCharacter(), $this->platform->getStringLiteralQuoteCharacter());
1175
    }
1176
1177
    protected function getQuotedCommentOnColumnSQLWithoutQuoteCharacter() : string
1178
    {
1179
        return "COMMENT ON COLUMN mytable.id IS 'This is a comment'";
1180
    }
1181
1182
    public function testGetCommentOnColumnSQLWithoutQuoteCharacter() : void
1183
    {
1184
        self::assertEquals(
1185
            $this->getQuotedCommentOnColumnSQLWithoutQuoteCharacter(),
1186
            $this->platform->getCommentOnColumnSQL('mytable', 'id', 'This is a comment')
1187
        );
1188
    }
1189
1190
    protected function getQuotedCommentOnColumnSQLWithQuoteCharacter() : string
1191
    {
1192
        return "COMMENT ON COLUMN mytable.id IS 'It''s a quote !'";
1193
    }
1194
1195
    public function testGetCommentOnColumnSQLWithQuoteCharacter() : void
1196
    {
1197
        $c = $this->getStringLiteralQuoteCharacter();
1198
1199
        self::assertEquals(
1200
            $this->getQuotedCommentOnColumnSQLWithQuoteCharacter(),
1201
            $this->platform->getCommentOnColumnSQL('mytable', 'id', 'It' . $c . 's a quote !')
1202
        );
1203
    }
1204
1205
    /**
1206
     * @see testGetCommentOnColumnSQL
1207
     *
1208
     * @return string[]
1209
     */
1210
    abstract protected function getCommentOnColumnSQL() : array;
1211
1212
    /**
1213
     * @group DBAL-1004
1214
     */
1215
    public function testGetCommentOnColumnSQL() : void
1216
    {
1217
        self::assertSame(
1218
            $this->getCommentOnColumnSQL(),
1219
            [
1220
                $this->platform->getCommentOnColumnSQL('foo', 'bar', 'comment'), // regular identifiers
1221
                $this->platform->getCommentOnColumnSQL('`Foo`', '`BAR`', 'comment'), // explicitly quoted identifiers
1222
                $this->platform->getCommentOnColumnSQL('select', 'from', 'comment'), // reserved keyword identifiers
1223
            ]
1224
        );
1225
    }
1226
1227
    /**
1228
     * @group DBAL-1176
1229
     * @dataProvider getGeneratesInlineColumnCommentSQL
1230
     */
1231
    public function testGeneratesInlineColumnCommentSQL(?string $comment, string $expectedSql) : void
1232
    {
1233
        if (! $this->platform->supportsInlineColumnComments()) {
1234
            self::markTestSkipped(sprintf('%s does not support inline column comments.', get_class($this->platform)));
1235
        }
1236
1237
        self::assertSame($expectedSql, $this->platform->getInlineColumnCommentSQL($comment));
1238
    }
1239
1240
    /**
1241
     * @return mixed[][]
1242
     */
1243
    public static function getGeneratesInlineColumnCommentSQL() : iterable
1244
    {
1245
        return [
1246
            'regular comment' => ['Regular comment', static::getInlineColumnRegularCommentSQL()],
1247
            'comment requiring escaping' => [
1248
                sprintf(
1249
                    'Using inline comment delimiter %s works',
1250
                    static::getInlineColumnCommentDelimiter()
1251
                ),
1252
                static::getInlineColumnCommentRequiringEscapingSQL(),
1253
            ],
1254
            'empty comment' => ['', static::getInlineColumnEmptyCommentSQL()],
1255
        ];
1256
    }
1257
1258
    protected static function getInlineColumnCommentDelimiter() : string
1259
    {
1260
        return "'";
1261
    }
1262
1263
    protected static function getInlineColumnRegularCommentSQL() : string
1264
    {
1265
        return "COMMENT 'Regular comment'";
1266
    }
1267
1268
    protected static function getInlineColumnCommentRequiringEscapingSQL() : string
1269
    {
1270
        return "COMMENT 'Using inline comment delimiter '' works'";
1271
    }
1272
1273
    protected static function getInlineColumnEmptyCommentSQL() : string
1274
    {
1275
        return "COMMENT ''";
1276
    }
1277
1278
    protected function getQuotedStringLiteralWithoutQuoteCharacter() : string
1279
    {
1280
        return "'No quote'";
1281
    }
1282
1283
    protected function getQuotedStringLiteralWithQuoteCharacter() : string
1284
    {
1285
        return "'It''s a quote'";
1286
    }
1287
1288
    protected function getQuotedStringLiteralQuoteCharacter() : string
1289
    {
1290
        return "''''";
1291
    }
1292
1293
    /**
1294
     * @group DBAL-1176
1295
     */
1296
    public function testThrowsExceptionOnGeneratingInlineColumnCommentSQLIfUnsupported() : void
1297
    {
1298
        if ($this->platform->supportsInlineColumnComments()) {
1299
            self::markTestSkipped(sprintf('%s supports inline column comments.', get_class($this->platform)));
1300
        }
1301
1302
        $this->expectException(DBALException::class);
1303
        $this->expectExceptionMessage("Operation 'Doctrine\\DBAL\\Platforms\\AbstractPlatform::getInlineColumnCommentSQL' is not supported by platform.");
1304
        $this->expectExceptionCode(0);
1305
1306
        $this->platform->getInlineColumnCommentSQL('unsupported');
1307
    }
1308
1309
    public function testQuoteStringLiteral() : void
1310
    {
1311
        $c = $this->getStringLiteralQuoteCharacter();
1312
1313
        self::assertEquals(
1314
            $this->getQuotedStringLiteralWithoutQuoteCharacter(),
1315
            $this->platform->quoteStringLiteral('No quote')
1316
        );
1317
        self::assertEquals(
1318
            $this->getQuotedStringLiteralWithQuoteCharacter(),
1319
            $this->platform->quoteStringLiteral('It' . $c . 's a quote')
1320
        );
1321
        self::assertEquals(
1322
            $this->getQuotedStringLiteralQuoteCharacter(),
1323
            $this->platform->quoteStringLiteral($c)
1324
        );
1325
    }
1326
1327
    /**
1328
     * @group DBAL-423
1329
     */
1330
    public function testReturnsGuidTypeDeclarationSQL() : void
1331
    {
1332
        $this->expectException(DBALException::class);
1333
1334
        $this->platform->getGuidTypeDeclarationSQL([]);
1335
    }
1336
1337
    /**
1338
     * @group DBAL-1010
1339
     */
1340
    public function testGeneratesAlterTableRenameColumnSQL() : void
1341
    {
1342
        $table = new Table('foo');
1343
        $table->addColumn(
1344
            'bar',
1345
            'integer',
1346
            ['notnull' => true, 'default' => 666, 'comment' => 'rename test']
1347
        );
1348
1349
        $tableDiff                        = new TableDiff('foo');
1350
        $tableDiff->fromTable             = $table;
1351
        $tableDiff->renamedColumns['bar'] = new Column(
1352
            'baz',
1353
            Type::getType('integer'),
1354
            ['notnull' => true, 'default' => 666, 'comment' => 'rename test']
1355
        );
1356
1357
        self::assertSame($this->getAlterTableRenameColumnSQL(), $this->platform->getAlterTableSQL($tableDiff));
1358
    }
1359
1360
    /**
1361
     * @return string[]
1362
     */
1363
    abstract public function getAlterTableRenameColumnSQL() : array;
1364
1365
    /**
1366
     * @group DBAL-1016
1367
     */
1368
    public function testQuotesTableIdentifiersInAlterTableSQL() : void
1369
    {
1370
        $table = new Table('"foo"');
1371
        $table->addColumn('id', 'integer');
1372
        $table->addColumn('fk', 'integer');
1373
        $table->addColumn('fk2', 'integer');
1374
        $table->addColumn('fk3', 'integer');
1375
        $table->addColumn('bar', 'integer');
1376
        $table->addColumn('baz', 'integer');
1377
        $table->addForeignKeyConstraint('fk_table', ['fk'], ['id'], [], 'fk1');
1378
        $table->addForeignKeyConstraint('fk_table', ['fk2'], ['id'], [], 'fk2');
1379
1380
        $tableDiff                        = new TableDiff('"foo"');
1381
        $tableDiff->fromTable             = $table;
1382
        $tableDiff->newName               = 'table';
1383
        $tableDiff->addedColumns['bloo']  = new Column('bloo', Type::getType('integer'));
1384
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
1385
            'bar',
1386
            new Column('bar', Type::getType('integer'), ['notnull' => false]),
1387
            ['notnull'],
1388
            $table->getColumn('bar')
1389
        );
1390
        $tableDiff->renamedColumns['id']  = new Column('war', Type::getType('integer'));
1391
        $tableDiff->removedColumns['baz'] = new Column('baz', Type::getType('integer'));
1392
        $tableDiff->addedForeignKeys[]    = new ForeignKeyConstraint(['fk3'], 'fk_table', ['id'], 'fk_add');
1393
        $tableDiff->changedForeignKeys[]  = new ForeignKeyConstraint(['fk2'], 'fk_table2', ['id'], 'fk2');
1394
        $tableDiff->removedForeignKeys[]  = new ForeignKeyConstraint(['fk'], 'fk_table', ['id'], 'fk1');
1395
1396
        self::assertSame(
1397
            $this->getQuotesTableIdentifiersInAlterTableSQL(),
1398
            $this->platform->getAlterTableSQL($tableDiff)
1399
        );
1400
    }
1401
1402
    /**
1403
     * @return string[]
1404
     */
1405
    abstract protected function getQuotesTableIdentifiersInAlterTableSQL() : array;
1406
1407
    /**
1408
     * @group DBAL-1090
1409
     */
1410
    public function testAlterStringToFixedString() : void
1411
    {
1412
        $table = new Table('mytable');
1413
        $table->addColumn('name', 'string', ['length' => 2]);
1414
1415
        $tableDiff            = new TableDiff('mytable');
1416
        $tableDiff->fromTable = $table;
1417
1418
        $tableDiff->changedColumns['name'] = new ColumnDiff(
1419
            'name',
1420
            new Column(
1421
                'name',
1422
                Type::getType('string'),
1423
                ['fixed' => true, 'length' => 2]
1424
            ),
1425
            ['fixed']
1426
        );
1427
1428
        $sql = $this->platform->getAlterTableSQL($tableDiff);
1429
1430
        $expectedSql = $this->getAlterStringToFixedStringSQL();
1431
1432
        self::assertEquals($expectedSql, $sql);
1433
    }
1434
1435
    /**
1436
     * @return string[]
1437
     */
1438
    abstract protected function getAlterStringToFixedStringSQL() : array;
1439
1440
    /**
1441
     * @group DBAL-1062
1442
     */
1443
    public function testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : void
1444
    {
1445
        $foreignTable = new Table('foreign_table');
1446
        $foreignTable->addColumn('id', 'integer');
1447
        $foreignTable->setPrimaryKey(['id']);
1448
1449
        $primaryTable = new Table('mytable');
1450
        $primaryTable->addColumn('foo', 'integer');
1451
        $primaryTable->addColumn('bar', 'integer');
1452
        $primaryTable->addColumn('baz', 'integer');
1453
        $primaryTable->addIndex(['foo'], 'idx_foo');
1454
        $primaryTable->addIndex(['bar'], 'idx_bar');
1455
        $primaryTable->addForeignKeyConstraint($foreignTable, ['foo'], ['id'], [], 'fk_foo');
1456
        $primaryTable->addForeignKeyConstraint($foreignTable, ['bar'], ['id'], [], 'fk_bar');
1457
1458
        $tableDiff                            = new TableDiff('mytable');
1459
        $tableDiff->fromTable                 = $primaryTable;
1460
        $tableDiff->renamedIndexes['idx_foo'] = new Index('idx_foo_renamed', ['foo']);
1461
1462
        self::assertSame(
1463
            $this->getGeneratesAlterTableRenameIndexUsedByForeignKeySQL(),
1464
            $this->platform->getAlterTableSQL($tableDiff)
1465
        );
1466
    }
1467
1468
    /**
1469
     * @return string[]
1470
     */
1471
    abstract protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array;
1472
1473
    /**
1474
     * @param mixed[] $column
1475
     *
1476
     * @group DBAL-1082
1477
     * @dataProvider getGeneratesDecimalTypeDeclarationSQL
1478
     */
1479
    public function testGeneratesDecimalTypeDeclarationSQL(array $column, string $expectedSql) : void
1480
    {
1481
        self::assertSame($expectedSql, $this->platform->getDecimalTypeDeclarationSQL($column));
1482
    }
1483
1484
    /**
1485
     * @return mixed[][]
1486
     */
1487
    public static function getGeneratesDecimalTypeDeclarationSQL() : iterable
1488
    {
1489
        return [
1490
            [[], 'NUMERIC(10, 0)'],
1491
            [['unsigned' => true], 'NUMERIC(10, 0)'],
1492
            [['unsigned' => false], 'NUMERIC(10, 0)'],
1493
            [['precision' => 5], 'NUMERIC(5, 0)'],
1494
            [['scale' => 5], 'NUMERIC(10, 5)'],
1495
            [['precision' => 8, 'scale' => 2], 'NUMERIC(8, 2)'],
1496
        ];
1497
    }
1498
1499
    /**
1500
     * @param mixed[] $column
1501
     *
1502
     * @group DBAL-1082
1503
     * @dataProvider getGeneratesFloatDeclarationSQL
1504
     */
1505
    public function testGeneratesFloatDeclarationSQL(array $column, string $expectedSql) : void
1506
    {
1507
        self::assertSame($expectedSql, $this->platform->getFloatDeclarationSQL($column));
1508
    }
1509
1510
    /**
1511
     * @return mixed[][]
1512
     */
1513
    public static function getGeneratesFloatDeclarationSQL() : iterable
1514
    {
1515
        return [
1516
            [[], 'DOUBLE PRECISION'],
1517
            [['unsigned' => true], 'DOUBLE PRECISION'],
1518
            [['unsigned' => false], 'DOUBLE PRECISION'],
1519
            [['precision' => 5], 'DOUBLE PRECISION'],
1520
            [['scale' => 5], 'DOUBLE PRECISION'],
1521
            [['precision' => 8, 'scale' => 2], 'DOUBLE PRECISION'],
1522
        ];
1523
    }
1524
1525
    public function testItEscapesStringsForLike() : void
1526
    {
1527
        self::assertSame(
1528
            '\_25\% off\_ your next purchase \\\\o/',
1529
            $this->platform->escapeStringForLike('_25% off_ your next purchase \o/', '\\')
1530
        );
1531
    }
1532
1533
    public function testZeroOffsetWithoutLimitIsIgnored() : void
1534
    {
1535
        $query = 'SELECT * FROM user';
1536
1537
        self::assertSame(
1538
            $query,
1539
            $this->platform->modifyLimitQuery($query, null, 0)
1540
        );
1541
    }
1542
}
1543