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

testGetSequencePrefixWithoutSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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
        $idx = new Index('constraint_name', ['test'], true, false);
256
        $sql = $this->platform->getCreateConstraintSQL($idx, 'test');
257
        self::assertEquals($this->getGenerateConstraintUniqueIndexSql(), $sql);
258
259
        $pk  = new Index('constraint_name', ['test'], true, true);
260
        $sql = $this->platform->getCreateConstraintSQL($pk, 'test');
261
        self::assertEquals($this->getGenerateConstraintPrimaryIndexSql(), $sql);
262
263
        $fk  = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk');
264
        $sql = $this->platform->getCreateConstraintSQL($fk, 'test');
265
        self::assertEquals($this->getGenerateConstraintForeignKeySql($fk), $sql);
266
    }
267
268
    public function testGeneratesForeignKeySqlOnlyWhenSupportingForeignKeys() : void
269
    {
270
        $fk = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk');
271
272
        if ($this->platform->supportsForeignKeyConstraints()) {
273
            self::assertIsString($this->platform->getCreateForeignKeySQL($fk, 'test'));
274
        } else {
275
            $this->expectException(DBALException::class);
276
            $this->platform->getCreateForeignKeySQL($fk, 'test');
277
        }
278
    }
279
280
    protected function getBitAndComparisonExpressionSql(string $value1, string $value2) : string
281
    {
282
        return '(' . $value1 . ' & ' . $value2 . ')';
283
    }
284
285
    /**
286
     * @group DDC-1213
287
     */
288
    public function testGeneratesBitAndComparisonExpressionSql() : void
289
    {
290
        $sql = $this->platform->getBitAndComparisonExpression(2, 4);
291
        self::assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql);
292
    }
293
294
    protected function getBitOrComparisonExpressionSql(string $value1, string $value2) : string
295
    {
296
        return '(' . $value1 . ' | ' . $value2 . ')';
297
    }
298
299
    /**
300
     * @group DDC-1213
301
     */
302
    public function testGeneratesBitOrComparisonExpressionSql() : void
303
    {
304
        $sql = $this->platform->getBitOrComparisonExpression(2, 4);
305
        self::assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql);
306
    }
307
308
    public function getGenerateConstraintUniqueIndexSql() : string
309
    {
310
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)';
311
    }
312
313
    public function getGenerateConstraintPrimaryIndexSql() : string
314
    {
315
        return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)';
316
    }
317
318
    public function getGenerateConstraintForeignKeySql(ForeignKeyConstraint $fk) : string
319
    {
320
        $quotedForeignTable = $fk->getQuotedForeignTableName($this->platform);
321
322
        return sprintf(
323
            'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES %s (id)',
324
            $quotedForeignTable
325
        );
326
    }
327
328
    /**
329
     * @return string[]
330
     */
331
    abstract public function getGenerateAlterTableSql() : array;
332
333
    public function testGeneratesTableAlterationSql() : void
334
    {
335
        $expectedSql = $this->getGenerateAlterTableSql();
336
337
        $table = new Table('mytable');
338
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
339
        $table->addColumn('foo', 'integer');
340
        $table->addColumn('bar', 'string');
341
        $table->addColumn('bloo', 'boolean');
342
        $table->setPrimaryKey(['id']);
343
344
        $tableDiff                         = new TableDiff('mytable');
345
        $tableDiff->fromTable              = $table;
346
        $tableDiff->newName                = 'userlist';
347
        $tableDiff->addedColumns['quota']  = new Column('quota', Type::getType('integer'), ['notnull' => false]);
348
        $tableDiff->removedColumns['foo']  = new Column('foo', Type::getType('integer'));
349
        $tableDiff->changedColumns['bar']  = new ColumnDiff(
350
            'bar',
351
            new Column(
352
                'baz',
353
                Type::getType('string'),
354
                ['default' => 'def']
355
            ),
356
            ['type', 'notnull', 'default']
357
        );
358
        $tableDiff->changedColumns['bloo'] = new ColumnDiff(
359
            'bloo',
360
            new Column(
361
                'bloo',
362
                Type::getType('boolean'),
363
                ['default' => false]
364
            ),
365
            ['type', 'notnull', 'default']
366
        );
367
368
        $sql = $this->platform->getAlterTableSQL($tableDiff);
369
370
        self::assertEquals($expectedSql, $sql);
371
    }
372
373
    public function testGetCustomColumnDeclarationSql() : void
374
    {
375
        $field = ['columnDefinition' => 'MEDIUMINT(6) UNSIGNED'];
376
        self::assertEquals('foo MEDIUMINT(6) UNSIGNED', $this->platform->getColumnDeclarationSQL('foo', $field));
377
    }
378
379
    public function testGetCreateTableSqlDispatchEvent() : void
380
    {
381
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetCreateTableSqlDispatchEvenListener'))
382
            ->addMethods(['onSchemaCreateTable', 'onSchemaCreateTableColumn'])
383
            ->getMock();
384
        $listenerMock
385
            ->expects(self::once())
386
            ->method('onSchemaCreateTable');
387
        $listenerMock
388
            ->expects(self::exactly(2))
389
            ->method('onSchemaCreateTableColumn');
390
391
        $eventManager = new EventManager();
392
        $eventManager->addEventListener([Events::onSchemaCreateTable, Events::onSchemaCreateTableColumn], $listenerMock);
393
394
        $this->platform->setEventManager($eventManager);
395
396
        $table = new Table('test');
397
        $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]);
398
        $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]);
399
400
        $this->platform->getCreateTableSQL($table);
401
    }
402
403
    public function testGetDropTableSqlDispatchEvent() : void
404
    {
405
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetDropTableSqlDispatchEventListener'))
406
            ->addMethods(['onSchemaDropTable'])
407
            ->getMock();
408
        $listenerMock
409
            ->expects(self::once())
410
            ->method('onSchemaDropTable');
411
412
        $eventManager = new EventManager();
413
        $eventManager->addEventListener([Events::onSchemaDropTable], $listenerMock);
414
415
        $this->platform->setEventManager($eventManager);
416
417
        $this->platform->getDropTableSQL('TABLE');
418
    }
419
420
    public function testGetAlterTableSqlDispatchEvent() : void
421
    {
422
        $events = [
423
            'onSchemaAlterTable',
424
            'onSchemaAlterTableAddColumn',
425
            'onSchemaAlterTableRemoveColumn',
426
            'onSchemaAlterTableChangeColumn',
427
            'onSchemaAlterTableRenameColumn',
428
        ];
429
430
        $listenerMock = $this->getMockBuilder($this->getMockClass('GetAlterTableSqlDispatchEvenListener'))
431
            ->addMethods($events)
432
            ->getMock();
433
        $listenerMock
434
            ->expects(self::once())
435
            ->method('onSchemaAlterTable');
436
        $listenerMock
437
            ->expects(self::once())
438
            ->method('onSchemaAlterTableAddColumn');
439
        $listenerMock
440
            ->expects(self::once())
441
            ->method('onSchemaAlterTableRemoveColumn');
442
        $listenerMock
443
            ->expects(self::once())
444
            ->method('onSchemaAlterTableChangeColumn');
445
        $listenerMock
446
            ->expects(self::once())
447
            ->method('onSchemaAlterTableRenameColumn');
448
449
        $eventManager = new EventManager();
450
        $events       = [
451
            Events::onSchemaAlterTable,
452
            Events::onSchemaAlterTableAddColumn,
453
            Events::onSchemaAlterTableRemoveColumn,
454
            Events::onSchemaAlterTableChangeColumn,
455
            Events::onSchemaAlterTableRenameColumn,
456
        ];
457
        $eventManager->addEventListener($events, $listenerMock);
458
459
        $this->platform->setEventManager($eventManager);
460
461
        $table = new Table('mytable');
462
        $table->addColumn('removed', 'integer');
463
        $table->addColumn('changed', 'integer');
464
        $table->addColumn('renamed', 'integer');
465
466
        $tableDiff                            = new TableDiff('mytable');
467
        $tableDiff->fromTable                 = $table;
468
        $tableDiff->addedColumns['added']     = new Column('added', Type::getType('integer'), []);
469
        $tableDiff->removedColumns['removed'] = new Column('removed', Type::getType('integer'), []);
470
        $tableDiff->changedColumns['changed'] = new ColumnDiff(
471
            'changed',
472
            new Column(
473
                'changed2',
474
                Type::getType('string'),
475
                []
476
            ),
477
            []
478
        );
479
        $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer'), []);
480
481
        $this->platform->getAlterTableSQL($tableDiff);
482
    }
483
484
    /**
485
     * @group DBAL-42
486
     */
487
    public function testCreateTableColumnComments() : void
488
    {
489
        $table = new Table('test');
490
        $table->addColumn('id', 'integer', ['comment' => 'This is a comment']);
491
        $table->setPrimaryKey(['id']);
492
493
        self::assertEquals($this->getCreateTableColumnCommentsSQL(), $this->platform->getCreateTableSQL($table));
494
    }
495
496
    /**
497
     * @group DBAL-42
498
     */
499
    public function testAlterTableColumnComments() : void
500
    {
501
        $tableDiff                        = new TableDiff('mytable');
502
        $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']);
503
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
504
            'foo',
505
            new Column(
506
                'foo',
507
                Type::getType('string')
508
            ),
509
            ['comment']
510
        );
511
        $tableDiff->changedColumns['bar'] = new ColumnDiff(
512
            'bar',
513
            new Column(
514
                'baz',
515
                Type::getType('string'),
516
                ['comment' => 'B comment']
517
            ),
518
            ['comment']
519
        );
520
521
        self::assertEquals($this->getAlterTableColumnCommentsSQL(), $this->platform->getAlterTableSQL($tableDiff));
522
    }
523
524
    public function testCreateTableColumnTypeComments() : void
525
    {
526
        $table = new Table('test');
527
        $table->addColumn('id', 'integer');
528
        $table->addColumn('data', 'array');
529
        $table->setPrimaryKey(['id']);
530
531
        self::assertEquals($this->getCreateTableColumnTypeCommentsSQL(), $this->platform->getCreateTableSQL($table));
532
    }
533
534
    /**
535
     * @return string[]
536
     */
537
    public function getCreateTableColumnCommentsSQL() : 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 getAlterTableColumnCommentsSQL() : 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
    /**
551
     * @return string[]
552
     */
553
    public function getCreateTableColumnTypeCommentsSQL() : array
554
    {
555
        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...
556
    }
557
558
    public function testGetDefaultValueDeclarationSQL() : void
559
    {
560
        // non-timestamp value will get single quotes
561
        $field = [
562
            'type' => Type::getType('string'),
563
            'default' => 'non_timestamp',
564
        ];
565
566
        self::assertEquals(" DEFAULT 'non_timestamp'", $this->platform->getDefaultValueDeclarationSQL($field));
567
    }
568
569
    /**
570
     * @group 2859
571
     */
572
    public function testGetDefaultValueDeclarationSQLDateTime() : void
573
    {
574
        // timestamps on datetime types should not be quoted
575
        foreach (['datetime', 'datetimetz', 'datetime_immutable', 'datetimetz_immutable'] as $type) {
576
            $field = [
577
                'type'    => Type::getType($type),
578
                'default' => $this->platform->getCurrentTimestampSQL(),
579
            ];
580
581
            self::assertSame(
582
                ' DEFAULT ' . $this->platform->getCurrentTimestampSQL(),
583
                $this->platform->getDefaultValueDeclarationSQL($field)
584
            );
585
        }
586
    }
587
588
    public function testGetDefaultValueDeclarationSQLForIntegerTypes() : void
589
    {
590
        foreach (['bigint', 'integer', 'smallint'] as $type) {
591
            $field = [
592
                'type'    => Type::getType($type),
593
                'default' => 1,
594
            ];
595
596
            self::assertEquals(
597
                ' DEFAULT 1',
598
                $this->platform->getDefaultValueDeclarationSQL($field)
599
            );
600
        }
601
    }
602
603
    /**
604
     * @group 2859
605
     */
606
    public function testGetDefaultValueDeclarationSQLForDateType() : void
607
    {
608
        $currentDateSql = $this->platform->getCurrentDateSQL();
609
        foreach (['date', 'date_immutable'] as $type) {
610
            $field = [
611
                'type'    => Type::getType($type),
612
                'default' => $currentDateSql,
613
            ];
614
615
            self::assertSame(
616
                ' DEFAULT ' . $currentDateSql,
617
                $this->platform->getDefaultValueDeclarationSQL($field)
618
            );
619
        }
620
    }
621
622
    /**
623
     * @group DBAL-45
624
     */
625
    public function testKeywordList() : void
626
    {
627
        $keywordList = $this->platform->getReservedKeywordsList();
628
        self::assertInstanceOf(KeywordList::class, $keywordList);
629
630
        self::assertTrue($keywordList->isKeyword('table'));
631
    }
632
633
    /**
634
     * @group DBAL-374
635
     */
636
    public function testQuotedColumnInPrimaryKeyPropagation() : void
637
    {
638
        $table = new Table('`quoted`');
639
        $table->addColumn('create', 'string');
640
        $table->setPrimaryKey(['create']);
641
642
        $sql = $this->platform->getCreateTableSQL($table);
643
        self::assertEquals($this->getQuotedColumnInPrimaryKeySQL(), $sql);
644
    }
645
646
    /**
647
     * @return string[]
648
     */
649
    abstract protected function getQuotedColumnInPrimaryKeySQL() : array;
650
651
    /**
652
     * @return string[]
653
     */
654
    abstract protected function getQuotedColumnInIndexSQL() : array;
655
656
    /**
657
     * @return string[]
658
     */
659
    abstract protected function getQuotedNameInIndexSQL() : array;
660
661
    /**
662
     * @return string[]
663
     */
664
    abstract protected function getQuotedColumnInForeignKeySQL() : array;
665
666
    /**
667
     * @group DBAL-374
668
     */
669
    public function testQuotedColumnInIndexPropagation() : void
670
    {
671
        $table = new Table('`quoted`');
672
        $table->addColumn('create', 'string');
673
        $table->addIndex(['create']);
674
675
        $sql = $this->platform->getCreateTableSQL($table);
676
        self::assertEquals($this->getQuotedColumnInIndexSQL(), $sql);
677
    }
678
679
    public function testQuotedNameInIndexSQL() : void
680
    {
681
        $table = new Table('test');
682
        $table->addColumn('column1', 'string');
683
        $table->addIndex(['column1'], '`key`');
684
685
        $sql = $this->platform->getCreateTableSQL($table);
686
        self::assertEquals($this->getQuotedNameInIndexSQL(), $sql);
687
    }
688
689
    /**
690
     * @group DBAL-374
691
     */
692
    public function testQuotedColumnInForeignKeyPropagation() : void
693
    {
694
        $table = new Table('`quoted`');
695
        $table->addColumn('create', 'string');
696
        $table->addColumn('foo', 'string');
697
        $table->addColumn('`bar`', 'string');
698
699
        // Foreign table with reserved keyword as name (needs quotation).
700
        $foreignTable = new Table('foreign');
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_RESERVED_KEYWORD');
706
707
        // Foreign table with non-reserved keyword as name (does not need quotation).
708
        $foreignTable = new Table('foo');
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_NON_RESERVED_KEYWORD');
714
715
        // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
716
        $foreignTable = new Table('`foo-bar`');
717
        $foreignTable->addColumn('create', 'string');    // Foreign column with reserved keyword as name (needs quotation).
718
        $foreignTable->addColumn('bar', 'string');       // Foreign column with non-reserved keyword as name (does not need quotation).
719
        $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite).
720
721
        $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_INTENDED_QUOTATION');
722
723
        $sql = $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS);
724
        self::assertEquals($this->getQuotedColumnInForeignKeySQL(), $sql);
725
    }
726
727
    /**
728
     * @group DBAL-1051
729
     */
730
    public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : void
731
    {
732
        $constraint = new UniqueConstraint('select', ['foo'], [], []);
733
734
        self::assertSame(
735
            $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(),
736
            $this->platform->getUniqueConstraintDeclarationSQL('select', $constraint)
737
        );
738
    }
739
740
    abstract protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string;
741
742
    /**
743
     * @group DBAL-2270
744
     */
745
    public function testQuotesReservedKeywordInTruncateTableSQL() : void
746
    {
747
        self::assertSame(
748
            $this->getQuotesReservedKeywordInTruncateTableSQL(),
749
            $this->platform->getTruncateTableSQL('select')
750
        );
751
    }
752
753
    abstract protected function getQuotesReservedKeywordInTruncateTableSQL() : string;
754
755
    /**
756
     * @group DBAL-1051
757
     */
758
    public function testQuotesReservedKeywordInIndexDeclarationSQL() : void
759
    {
760
        $index = new Index('select', ['foo']);
761
762
        if (! $this->supportsInlineIndexDeclaration()) {
763
            $this->expectException(DBALException::class);
764
        }
765
766
        self::assertSame(
767
            $this->getQuotesReservedKeywordInIndexDeclarationSQL(),
768
            $this->platform->getIndexDeclarationSQL('select', $index)
769
        );
770
    }
771
772
    abstract protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string;
773
774
    protected function supportsInlineIndexDeclaration() : bool
775
    {
776
        return true;
777
    }
778
779
    public function testSupportsCommentOnStatement() : void
780
    {
781
        self::assertSame($this->supportsCommentOnStatement(), $this->platform->supportsCommentOnStatement());
782
    }
783
784
    protected function supportsCommentOnStatement() : bool
785
    {
786
        return false;
787
    }
788
789
    public function testGetCreateSchemaSQL() : void
790
    {
791
        $this->expectException(DBALException::class);
792
793
        $this->platform->getCreateSchemaSQL('schema');
794
    }
795
796
    /**
797
     * @group DBAL-585
798
     */
799
    public function testAlterTableChangeQuotedColumn() : void
800
    {
801
        $tableDiff                        = new TableDiff('mytable');
802
        $tableDiff->fromTable             = new Table('mytable');
803
        $tableDiff->changedColumns['foo'] = new ColumnDiff(
804
            'select',
805
            new Column(
806
                'select',
807
                Type::getType('string')
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
    public function testGetSequencePrefixWithoutSchema() : void
827
    {
828
        self::assertEquals('foo', $this->platform->getSequencePrefix('foo'));
829
    }
830
831
    public function testGetSequencePrefixWithSchema() : void
832
    {
833
        self::assertEquals('bar.foo', $this->platform->getSequencePrefix('foo', 'bar'));
834
    }
835
836
    /**
837
     * @group DBAL-563
838
     */
839
    public function testReturnsIdentitySequenceName() : void
840
    {
841
        $this->expectException(DBALException::class);
842
843
        $this->platform->getIdentitySequenceName('mytable', 'mycolumn');
844
    }
845
846
    public function testReturnsBinaryDefaultLength() : void
847
    {
848
        self::assertSame($this->getBinaryDefaultLength(), $this->platform->getBinaryDefaultLength());
849
    }
850
851
    protected function getBinaryDefaultLength() : int
852
    {
853
        return 255;
854
    }
855
856
    public function testReturnsBinaryMaxLength() : void
857
    {
858
        self::assertSame($this->getBinaryMaxLength(), $this->platform->getBinaryMaxLength());
859
    }
860
861
    protected function getBinaryMaxLength() : int
862
    {
863
        return 4000;
864
    }
865
866
    public function testReturnsBinaryTypeDeclarationSQL() : void
867
    {
868
        $this->expectException(DBALException::class);
869
870
        $this->platform->getBinaryTypeDeclarationSQL([]);
871
    }
872
873
    public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void
874
    {
875
        $this->markTestSkipped('Not applicable to the platform');
876
    }
877
878
    /**
879
     * @group DBAL-553
880
     */
881
    public function hasNativeJsonType() : void
882
    {
883
        self::assertFalse($this->platform->hasNativeJsonType());
884
    }
885
886
    /**
887
     * @group DBAL-553
888
     */
889
    public function testReturnsJsonTypeDeclarationSQL() : void
890
    {
891
        $column = [
892
            'length'  => 666,
893
            'notnull' => true,
894
            'type'    => Type::getType('json_array'),
895
        ];
896
897
        self::assertSame(
898
            $this->platform->getClobTypeDeclarationSQL($column),
899
            $this->platform->getJsonTypeDeclarationSQL($column)
900
        );
901
    }
902
903
    /**
904
     * @group DBAL-234
905
     */
906
    public function testAlterTableRenameIndex() : void
907
    {
908
        $tableDiff            = new TableDiff('mytable');
909
        $tableDiff->fromTable = new Table('mytable');
910
        $tableDiff->fromTable->addColumn('id', 'integer');
911
        $tableDiff->fromTable->setPrimaryKey(['id']);
912
        $tableDiff->renamedIndexes = [
913
            'idx_foo' => new Index('idx_bar', ['id']),
914
        ];
915
916
        self::assertSame(
917
            $this->getAlterTableRenameIndexSQL(),
918
            $this->platform->getAlterTableSQL($tableDiff)
919
        );
920
    }
921
922
    /**
923
     * @return string[]
924
     *
925
     * @group DBAL-234
926
     */
927
    protected function getAlterTableRenameIndexSQL() : array
928
    {
929
        return [
930
            'DROP INDEX idx_foo',
931
            'CREATE INDEX idx_bar ON mytable (id)',
932
        ];
933
    }
934
935
    /**
936
     * @group DBAL-234
937
     */
938
    public function testQuotesAlterTableRenameIndex() : void
939
    {
940
        $tableDiff            = new TableDiff('table');
941
        $tableDiff->fromTable = new Table('table');
942
        $tableDiff->fromTable->addColumn('id', 'integer');
943
        $tableDiff->fromTable->setPrimaryKey(['id']);
944
        $tableDiff->renamedIndexes = [
945
            'create' => new Index('select', ['id']),
946
            '`foo`'  => new Index('`bar`', ['id']),
947
        ];
948
949
        self::assertSame(
950
            $this->getQuotedAlterTableRenameIndexSQL(),
951
            $this->platform->getAlterTableSQL($tableDiff)
952
        );
953
    }
954
955
    /**
956
     * @return string[]
957
     *
958
     * @group DBAL-234
959
     */
960
    protected function getQuotedAlterTableRenameIndexSQL() : array
961
    {
962
        return [
963
            'DROP INDEX "create"',
964
            'CREATE INDEX "select" ON "table" (id)',
965
            'DROP INDEX "foo"',
966
            'CREATE INDEX "bar" ON "table" (id)',
967
        ];
968
    }
969
970
    /**
971
     * @group DBAL-835
972
     */
973
    public function testQuotesAlterTableRenameColumn() : void
974
    {
975
        $fromTable = new Table('mytable');
976
977
        $fromTable->addColumn('unquoted1', 'integer', ['comment' => 'Unquoted 1']);
978
        $fromTable->addColumn('unquoted2', 'integer', ['comment' => 'Unquoted 2']);
979
        $fromTable->addColumn('unquoted3', 'integer', ['comment' => 'Unquoted 3']);
980
981
        $fromTable->addColumn('create', 'integer', ['comment' => 'Reserved keyword 1']);
982
        $fromTable->addColumn('table', 'integer', ['comment' => 'Reserved keyword 2']);
983
        $fromTable->addColumn('select', 'integer', ['comment' => 'Reserved keyword 3']);
984
985
        $fromTable->addColumn('`quoted1`', 'integer', ['comment' => 'Quoted 1']);
986
        $fromTable->addColumn('`quoted2`', 'integer', ['comment' => 'Quoted 2']);
987
        $fromTable->addColumn('`quoted3`', 'integer', ['comment' => 'Quoted 3']);
988
989
        $toTable = new Table('mytable');
990
991
        $toTable->addColumn('unquoted', 'integer', ['comment' => 'Unquoted 1']); // unquoted -> unquoted
992
        $toTable->addColumn('where', 'integer', ['comment' => 'Unquoted 2']); // unquoted -> reserved keyword
993
        $toTable->addColumn('`foo`', 'integer', ['comment' => 'Unquoted 3']); // unquoted -> quoted
994
995
        $toTable->addColumn('reserved_keyword', 'integer', ['comment' => 'Reserved keyword 1']); // reserved keyword -> unquoted
996
        $toTable->addColumn('from', 'integer', ['comment' => 'Reserved keyword 2']); // reserved keyword -> reserved keyword
997
        $toTable->addColumn('`bar`', 'integer', ['comment' => 'Reserved keyword 3']); // reserved keyword -> quoted
998
999
        $toTable->addColumn('quoted', 'integer', ['comment' => 'Quoted 1']); // quoted -> unquoted
1000
        $toTable->addColumn('and', 'integer', ['comment' => 'Quoted 2']); // quoted -> reserved keyword
1001
        $toTable->addColumn('`baz`', 'integer', ['comment' => 'Quoted 3']); // quoted -> quoted
1002
1003
        $comparator = new Comparator();
1004
1005
        self::assertEquals(
1006
            $this->getQuotedAlterTableRenameColumnSQL(),
1007
            $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

1007
            $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $comparator->diffTable($fromTable, $toTable))
Loading history...
1008
        );
1009
    }
1010
1011
    /**
1012
     * Returns SQL statements for {@link testQuotesAlterTableRenameColumn}.
1013
     *
1014
     * @return string[]
1015
     *
1016
     * @group DBAL-835
1017
     */
1018
    abstract protected function getQuotedAlterTableRenameColumnSQL() : array;
1019
1020
    /**
1021
     * @group DBAL-835
1022
     */
1023
    public function testQuotesAlterTableChangeColumnLength() : void
1024
    {
1025
        $fromTable = new Table('mytable');
1026
1027
        $fromTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 10]);
1028
        $fromTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 10]);
1029
        $fromTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 10]);
1030
1031
        $fromTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 10]);
1032
        $fromTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 10]);
1033
        $fromTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 10]);
1034
1035
        $toTable = new Table('mytable');
1036
1037
        $toTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 255]);
1038
        $toTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 255]);
1039
        $toTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 255]);
1040
1041
        $toTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 255]);
1042
        $toTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 255]);
1043
        $toTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 255]);
1044
1045
        $comparator = new Comparator();
1046
1047
        self::assertEquals(
1048
            $this->getQuotedAlterTableChangeColumnLengthSQL(),
1049
            $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

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