Failed Conditions
Pull Request — develop (#3348)
by Sergei
60:53
created

testGetNullCommentOnColumnSQL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Platforms;
6
7
use Doctrine\DBAL\Schema\Column;
8
use Doctrine\DBAL\Schema\ColumnDiff;
9
use Doctrine\DBAL\Schema\Comparator;
10
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
11
use Doctrine\DBAL\Schema\Sequence;
12
use Doctrine\DBAL\Schema\Table;
13
use Doctrine\DBAL\Schema\TableDiff;
14
use Doctrine\DBAL\TransactionIsolationLevel;
15
use Doctrine\DBAL\Types\Type;
16
use UnexpectedValueException;
17
use function sprintf;
18
19
abstract class AbstractPostgreSqlPlatformTestCase extends AbstractPlatformTestCase
20
{
21
    public function getGenerateTableSql() : string
22
    {
23
        return 'CREATE TABLE test (id SERIAL NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
24
    }
25
26
    /**
27
     * {@inheritDoc}
28
     */
29
    public function getGenerateTableWithMultiColumnUniqueIndexSql() : array
30
    {
31
        return [
32
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
33
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
34
        ];
35
    }
36
37
    /**
38
     * {@inheritDoc}
39
     */
40
    public function getGenerateAlterTableSql() : array
41
    {
42
        return [
43
            'ALTER TABLE mytable ADD quota INT DEFAULT NULL',
44
            'ALTER TABLE mytable DROP foo',
45
            'ALTER TABLE mytable ALTER bar TYPE VARCHAR(255)',
46
            "ALTER TABLE mytable ALTER bar SET DEFAULT 'def'",
47
            'ALTER TABLE mytable ALTER bar SET NOT NULL',
48
            'ALTER TABLE mytable ALTER bloo TYPE BOOLEAN',
49
            "ALTER TABLE mytable ALTER bloo SET DEFAULT 'false'",
50
            'ALTER TABLE mytable ALTER bloo SET NOT NULL',
51
            'ALTER TABLE mytable RENAME TO userlist',
52
        ];
53
    }
54
55
    public function getGenerateIndexSql() : string
56
    {
57
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
58
    }
59
60
    public function getGenerateForeignKeySql() : string
61
    {
62
        return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE';
63
    }
64
65
    public function testGeneratesForeignKeySqlForNonStandardOptions() : void
66
    {
67
        $foreignKey = new ForeignKeyConstraint(
68
            ['foreign_id'],
69
            'my_table',
70
            ['id'],
71
            'my_fk',
72
            ['onDelete' => 'CASCADE']
73
        );
74
        self::assertEquals(
75
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE',
76
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
77
        );
78
79
        $foreignKey = new ForeignKeyConstraint(
80
            ['foreign_id'],
81
            'my_table',
82
            ['id'],
83
            'my_fk',
84
            ['match' => 'full']
85
        );
86
        self::assertEquals(
87
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full NOT DEFERRABLE INITIALLY IMMEDIATE',
88
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
89
        );
90
91
        $foreignKey = new ForeignKeyConstraint(
92
            ['foreign_id'],
93
            'my_table',
94
            ['id'],
95
            'my_fk',
96
            ['deferrable' => true]
97
        );
98
        self::assertEquals(
99
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) DEFERRABLE INITIALLY IMMEDIATE',
100
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
101
        );
102
103
        $foreignKey = new ForeignKeyConstraint(
104
            ['foreign_id'],
105
            'my_table',
106
            ['id'],
107
            'my_fk',
108
            ['deferred' => true]
109
        );
110
        self::assertEquals(
111
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
112
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
113
        );
114
115
        $foreignKey = new ForeignKeyConstraint(
116
            ['foreign_id'],
117
            'my_table',
118
            ['id'],
119
            'my_fk',
120
            ['deferred' => true]
121
        );
122
        self::assertEquals(
123
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
124
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
125
        );
126
127
        $foreignKey = new ForeignKeyConstraint(
128
            ['foreign_id'],
129
            'my_table',
130
            ['id'],
131
            'my_fk',
132
            ['deferrable' => true, 'deferred' => true, 'match' => 'full']
133
        );
134
        self::assertEquals(
135
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full DEFERRABLE INITIALLY DEFERRED',
136
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
137
        );
138
    }
139
140
    public function testGeneratesSqlSnippets() : void
141
    {
142
        self::assertEquals('SIMILAR TO', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct');
143
        self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct');
144
        self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct');
145
        self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct');
146
        self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', '1', '5'), 'Substring expression with length is not correct');
147
    }
148
149
    public function testGeneratesTransactionCommands() : void
150
    {
151
        self::assertEquals(
152
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
153
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED)
154
        );
155
        self::assertEquals(
156
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED',
157
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED)
158
        );
159
        self::assertEquals(
160
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ',
161
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ)
162
        );
163
        self::assertEquals(
164
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE',
165
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE)
166
        );
167
    }
168
169
    public function testGeneratesDDLSnippets() : void
170
    {
171
        self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar'));
172
        self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar'));
173
        self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar'));
174
    }
175
176
    public function testGenerateTableWithAutoincrement() : void
177
    {
178
        $table  = new Table('autoinc_table');
179
        $column = $table->addColumn('id', 'integer');
180
        $column->setAutoincrement(true);
181
182
        self::assertEquals(['CREATE TABLE autoinc_table (id SERIAL NOT NULL)'], $this->platform->getCreateTableSQL($table));
183
    }
184
185
    /**
186
     * @return mixed[][]
187
     */
188
    public static function serialTypes() : iterable
189
    {
190
        return [
191
            ['integer', 'SERIAL'],
192
            ['bigint', 'BIGSERIAL'],
193
        ];
194
    }
195
196
    /**
197
     * @dataProvider serialTypes
198
     * @group 2906
199
     */
200
    public function testGenerateTableWithAutoincrementDoesNotSetDefault(string $type, string $definition) : void
201
    {
202
        $table  = new Table('autoinc_table_notnull');
203
        $column = $table->addColumn('id', $type);
204
        $column->setAutoIncrement(true);
205
        $column->setNotNull(false);
206
207
        $sql = $this->platform->getCreateTableSQL($table);
208
209
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull (id %s)', $definition)], $sql);
210
    }
211
212
    /**
213
     * @dataProvider serialTypes
214
     * @group 2906
215
     */
216
    public function testCreateTableWithAutoincrementAndNotNullAddsConstraint(string $type, string $definition) : void
217
    {
218
        $table  = new Table('autoinc_table_notnull_enabled');
219
        $column = $table->addColumn('id', $type);
220
        $column->setAutoIncrement(true);
221
        $column->setNotNull(true);
222
223
        $sql = $this->platform->getCreateTableSQL($table);
224
225
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull_enabled (id %s NOT NULL)', $definition)], $sql);
226
    }
227
228
    /**
229
     * @dataProvider serialTypes
230
     * @group 2906
231
     */
232
    public function testGetDefaultValueDeclarationSQLIgnoresTheDefaultKeyWhenTheFieldIsSerial(string $type) : void
233
    {
234
        $sql = $this->platform->getDefaultValueDeclarationSQL(
235
            [
236
                'autoincrement' => true,
237
                'type'          => Type::getType($type),
238
                'default'       => 1,
239
            ]
240
        );
241
242
        self::assertSame('', $sql);
243
    }
244
245
    public function testGeneratesTypeDeclarationForIntegers() : void
246
    {
247
        self::assertEquals(
248
            'INT',
249
            $this->platform->getIntegerTypeDeclarationSQL([])
250
        );
251
        self::assertEquals(
252
            'SERIAL',
253
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true])
254
        );
255
        self::assertEquals(
256
            'SERIAL',
257
            $this->platform->getIntegerTypeDeclarationSQL(
258
                ['autoincrement' => true, 'primary' => true]
259
            )
260
        );
261
    }
262
263
    public function testGeneratesTypeDeclarationForStrings() : void
264
    {
265
        self::assertEquals(
266
            'CHAR(10)',
267
            $this->platform->getVarcharTypeDeclarationSQL(
268
                ['length' => 10, 'fixed' => true]
269
            )
270
        );
271
        self::assertEquals(
272
            'VARCHAR(50)',
273
            $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]),
274
            'Variable string declaration is not correct'
275
        );
276
        self::assertEquals(
277
            'VARCHAR(255)',
278
            $this->platform->getVarcharTypeDeclarationSQL([]),
279
            'Long string declaration is not correct'
280
        );
281
    }
282
283
    public function getGenerateUniqueIndexSql() : string
284
    {
285
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
286
    }
287
288
    public function testGeneratesSequenceSqlCommands() : void
289
    {
290
        $sequence = new Sequence('myseq', 20, 1);
291
        self::assertEquals(
292
            'CREATE SEQUENCE myseq INCREMENT BY 20 MINVALUE 1 START 1',
293
            $this->platform->getCreateSequenceSQL($sequence)
294
        );
295
        self::assertEquals(
296
            'DROP SEQUENCE myseq CASCADE',
297
            $this->platform->getDropSequenceSQL('myseq')
298
        );
299
        self::assertEquals(
300
            "SELECT NEXTVAL('myseq')",
301
            $this->platform->getSequenceNextValSQL('myseq')
302
        );
303
    }
304
305
    public function testDoesNotPreferIdentityColumns() : void
306
    {
307
        self::assertFalse($this->platform->prefersIdentityColumns());
308
    }
309
310
    public function testPrefersSequences() : void
311
    {
312
        self::assertTrue($this->platform->prefersSequences());
313
    }
314
315
    public function testSupportsIdentityColumns() : void
316
    {
317
        self::assertTrue($this->platform->supportsIdentityColumns());
318
    }
319
320
    public function testSupportsSavePoints() : void
321
    {
322
        self::assertTrue($this->platform->supportsSavepoints());
323
    }
324
325
    public function testSupportsSequences() : void
326
    {
327
        self::assertTrue($this->platform->supportsSequences());
328
    }
329
330
    /**
331
     * {@inheritdoc}
332
     */
333
    protected function supportsCommentOnStatement() : bool
334
    {
335
        return true;
336
    }
337
338
    public function testModifyLimitQuery() : void
339
    {
340
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
341
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
342
    }
343
344
    public function testModifyLimitQueryWithEmptyOffset() : void
345
    {
346
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
347
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
348
    }
349
350
    /**
351
     * {@inheritDoc}
352
     */
353
    public function getCreateTableColumnCommentsSQL() : array
354
    {
355
        return [
356
            'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))',
357
            "COMMENT ON COLUMN test.id IS 'This is a comment'",
358
        ];
359
    }
360
361
    /**
362
     * {@inheritDoc}
363
     */
364
    public function getAlterTableColumnCommentsSQL() : array
365
    {
366
        return [
367
            'ALTER TABLE mytable ADD quota INT NOT NULL',
368
            "COMMENT ON COLUMN mytable.quota IS 'A comment'",
369
            'COMMENT ON COLUMN mytable.foo IS NULL',
370
            "COMMENT ON COLUMN mytable.baz IS 'B comment'",
371
        ];
372
    }
373
374
    /**
375
     * {@inheritDoc}
376
     */
377
    public function getCreateTableColumnTypeCommentsSQL() : array
378
    {
379
        return [
380
            'CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))',
381
            "COMMENT ON COLUMN test.data IS '(DC2Type:array)'",
382
        ];
383
    }
384
385
    /**
386
     * {@inheritDoc}
387
     */
388
    protected function getQuotedColumnInPrimaryKeySQL() : array
389
    {
390
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
391
    }
392
393
    /**
394
     * {@inheritDoc}
395
     */
396
    protected function getQuotedColumnInIndexSQL() : array
397
    {
398
        return [
399
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
400
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
401
        ];
402
    }
403
404
    /**
405
     * {@inheritDoc}
406
     */
407
    protected function getQuotedNameInIndexSQL() : array
408
    {
409
        return [
410
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
411
            'CREATE INDEX "key" ON test (column1)',
412
        ];
413
    }
414
415
    /**
416
     * {@inheritDoc}
417
     */
418
    protected function getQuotedColumnInForeignKeySQL() : array
419
    {
420
        return [
421
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
422
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
423
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
424
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
425
        ];
426
    }
427
428
    /**
429
     * @group DBAL-457
430
     * @dataProvider pgBooleanProvider
431
     */
432
    public function testConvertBooleanAsLiteralStrings(
433
        string $databaseValue,
434
        string $preparedStatementValue,
435
        int $integerValue,
0 ignored issues
show
Unused Code introduced by
The parameter $integerValue is not used and could be removed. ( Ignorable by Annotation )

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

435
        /** @scrutinizer ignore-unused */ int $integerValue,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
436
        bool $booleanValue
0 ignored issues
show
Unused Code introduced by
The parameter $booleanValue is not used and could be removed. ( Ignorable by Annotation )

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

436
        /** @scrutinizer ignore-unused */ bool $booleanValue

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
437
    ) : void {
438
        $platform = $this->createPlatform();
439
440
        self::assertEquals($preparedStatementValue, $platform->convertBooleans($databaseValue));
441
    }
442
443
    /**
444
     * @group DBAL-457
445
     */
446
    public function testConvertBooleanAsLiteralIntegers() : void
447
    {
448
        $platform = $this->createPlatform();
449
        $platform->setUseBooleanTrueFalseStrings(false);
0 ignored issues
show
Bug introduced by
The method setUseBooleanTrueFalseStrings() does not exist on Doctrine\DBAL\Platforms\AbstractPlatform. It seems like you code against a sub-type of Doctrine\DBAL\Platforms\AbstractPlatform such as Doctrine\DBAL\Platforms\PostgreSqlPlatform. ( Ignorable by Annotation )

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

449
        $platform->/** @scrutinizer ignore-call */ 
450
                   setUseBooleanTrueFalseStrings(false);
Loading history...
450
451
        self::assertEquals(1, $platform->convertBooleans(true));
452
        self::assertEquals(1, $platform->convertBooleans('1'));
453
454
        self::assertEquals(0, $platform->convertBooleans(false));
455
        self::assertEquals(0, $platform->convertBooleans('0'));
456
    }
457
458
    /**
459
     * @group DBAL-630
460
     * @dataProvider pgBooleanProvider
461
     */
462
    public function testConvertBooleanAsDatabaseValueStrings(
463
        string $databaseValue,
0 ignored issues
show
Unused Code introduced by
The parameter $databaseValue is not used and could be removed. ( Ignorable by Annotation )

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

463
        /** @scrutinizer ignore-unused */ string $databaseValue,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
464
        string $preparedStatementValue,
0 ignored issues
show
Unused Code introduced by
The parameter $preparedStatementValue is not used and could be removed. ( Ignorable by Annotation )

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

464
        /** @scrutinizer ignore-unused */ string $preparedStatementValue,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
465
        int $integerValue,
466
        bool $booleanValue
467
    ) : void {
468
        $platform = $this->createPlatform();
469
470
        self::assertSame($integerValue, $platform->convertBooleansToDatabaseValue($booleanValue));
471
    }
472
473
    /**
474
     * @group DBAL-630
475
     */
476
    public function testConvertBooleanAsDatabaseValueIntegers() : void
477
    {
478
        $platform = $this->createPlatform();
479
        $platform->setUseBooleanTrueFalseStrings(false);
480
481
        self::assertSame(1, $platform->convertBooleansToDatabaseValue(true));
482
        self::assertSame(0, $platform->convertBooleansToDatabaseValue(false));
483
    }
484
485
    /**
486
     * @dataProvider pgBooleanProvider
487
     */
488
    public function testConvertFromBoolean(string $databaseValue, string $prepareStatementValue, int $integerValue, bool $booleanValue) : void
0 ignored issues
show
Unused Code introduced by
The parameter $integerValue is not used and could be removed. ( Ignorable by Annotation )

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

488
    public function testConvertFromBoolean(string $databaseValue, string $prepareStatementValue, /** @scrutinizer ignore-unused */ int $integerValue, bool $booleanValue) : void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $prepareStatementValue is not used and could be removed. ( Ignorable by Annotation )

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

488
    public function testConvertFromBoolean(string $databaseValue, /** @scrutinizer ignore-unused */ string $prepareStatementValue, int $integerValue, bool $booleanValue) : void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
489
    {
490
        $platform = $this->createPlatform();
491
492
        self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue));
493
    }
494
495
    public function testThrowsExceptionWithInvalidBooleanLiteral() : void
496
    {
497
        $platform = $this->createPlatform();
498
499
        $this->expectException(UnexpectedValueException::class);
500
        $this->expectExceptionMessage('Unrecognized boolean literal, my-bool given.');
501
502
        $platform->convertBooleansToDatabaseValue('my-bool');
503
    }
504
505
    public function testGetCreateSchemaSQL() : void
506
    {
507
        $schemaName = 'schema';
508
        $sql        = $this->platform->getCreateSchemaSQL($schemaName);
509
        self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql);
510
    }
511
512
    public function testAlterDecimalPrecisionScale() : void
513
    {
514
        $table = new Table('mytable');
515
        $table->addColumn('dfoo1', 'decimal');
516
        $table->addColumn('dfoo2', 'decimal', ['precision' => 10, 'scale' => 6]);
517
        $table->addColumn('dfoo3', 'decimal', ['precision' => 10, 'scale' => 6]);
518
        $table->addColumn('dfoo4', 'decimal', ['precision' => 10, 'scale' => 6]);
519
520
        $tableDiff            = new TableDiff('mytable');
521
        $tableDiff->fromTable = $table;
522
523
        $tableDiff->changedColumns['dloo1'] = new ColumnDiff(
524
            'dloo1',
525
            new Column(
526
                'dloo1',
527
                Type::getType('decimal'),
528
                ['precision' => 16, 'scale' => 6]
529
            ),
530
            ['precision']
531
        );
532
        $tableDiff->changedColumns['dloo2'] = new ColumnDiff(
533
            'dloo2',
534
            new Column(
535
                'dloo2',
536
                Type::getType('decimal'),
537
                ['precision' => 10, 'scale' => 4]
538
            ),
539
            ['scale']
540
        );
541
        $tableDiff->changedColumns['dloo3'] = new ColumnDiff(
542
            'dloo3',
543
            new Column(
544
                'dloo3',
545
                Type::getType('decimal'),
546
                ['precision' => 10, 'scale' => 6]
547
            ),
548
            []
549
        );
550
        $tableDiff->changedColumns['dloo4'] = new ColumnDiff(
551
            'dloo4',
552
            new Column(
553
                'dloo4',
554
                Type::getType('decimal'),
555
                ['precision' => 16, 'scale' => 8]
556
            ),
557
            ['precision', 'scale']
558
        );
559
560
        $sql = $this->platform->getAlterTableSQL($tableDiff);
561
562
        $expectedSql = [
563
            'ALTER TABLE mytable ALTER dloo1 TYPE NUMERIC(16, 6)',
564
            'ALTER TABLE mytable ALTER dloo2 TYPE NUMERIC(10, 4)',
565
            'ALTER TABLE mytable ALTER dloo4 TYPE NUMERIC(16, 8)',
566
        ];
567
568
        self::assertEquals($expectedSql, $sql);
569
    }
570
571
    /**
572
     * @group DBAL-365
573
     */
574
    public function testDroppingConstraintsBeforeColumns() : void
575
    {
576
        $newTable = new Table('mytable');
577
        $newTable->addColumn('id', 'integer');
578
        $newTable->setPrimaryKey(['id']);
579
580
        $oldTable = clone $newTable;
581
        $oldTable->addColumn('parent_id', 'integer');
582
        $oldTable->addForeignKeyConstraint('mytable', ['parent_id'], ['id']);
583
584
        $comparator = new Comparator();
585
        $tableDiff  = $comparator->diffTable($oldTable, $newTable);
586
587
        $sql = $this->platform->getAlterTableSQL($tableDiff);
588
589
        $expectedSql = [
590
            'ALTER TABLE mytable DROP CONSTRAINT FK_6B2BD609727ACA70',
591
            'DROP INDEX IDX_6B2BD609727ACA70',
592
            'ALTER TABLE mytable DROP parent_id',
593
        ];
594
595
        self::assertEquals($expectedSql, $sql);
596
    }
597
598
    /**
599
     * @group DBAL-563
600
     */
601
    public function testUsesSequenceEmulatedIdentityColumns() : void
602
    {
603
        self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns());
604
    }
605
606
    /**
607
     * @group DBAL-563
608
     */
609
    public function testReturnsIdentitySequenceName() : void
610
    {
611
        self::assertSame('mytable_mycolumn_seq', $this->platform->getIdentitySequenceName('mytable', 'mycolumn'));
612
    }
613
614
    /**
615
     * @dataProvider dataCreateSequenceWithCache
616
     * @group DBAL-139
617
     */
618
    public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void
619
    {
620
        $sequence = new Sequence('foo', 1, 1, $cacheSize);
621
        self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence));
622
    }
623
624
    /**
625
     * @return mixed[][]
626
     */
627
    public static function dataCreateSequenceWithCache() : iterable
628
    {
629
        return [
630
            [3, 'CACHE 3'],
631
        ];
632
    }
633
634
    protected function getBinaryDefaultLength() : int
635
    {
636
        return 0;
637
    }
638
639
    protected function getBinaryMaxLength() : int
640
    {
641
        return 0;
642
    }
643
644
    public function testReturnsBinaryTypeDeclarationSQL() : void
645
    {
646
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL([]));
647
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
648
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999]));
649
650
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
651
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
652
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999]));
653
    }
654
655
    public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void
656
    {
657
        $table1 = new Table('mytable');
658
        $table1->addColumn('column_varbinary', 'binary');
659
        $table1->addColumn('column_binary', 'binary', ['fixed' => true]);
660
        $table1->addColumn('column_blob', 'blob');
661
662
        $table2 = new Table('mytable');
663
        $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]);
664
        $table2->addColumn('column_binary', 'binary');
665
        $table2->addColumn('column_blob', 'binary');
666
667
        $comparator = new Comparator();
668
669
        // VARBINARY -> BINARY
670
        // BINARY    -> VARBINARY
671
        // BLOB      -> VARBINARY
672
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
673
674
        $table2 = new Table('mytable');
675
        $table2->addColumn('column_varbinary', 'binary', ['length' => 42]);
676
        $table2->addColumn('column_binary', 'blob');
677
        $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]);
678
679
        // VARBINARY -> VARBINARY with changed length
680
        // BINARY    -> BLOB
681
        // BLOB      -> BINARY
682
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
683
684
        $table2 = new Table('mytable');
685
        $table2->addColumn('column_varbinary', 'blob');
686
        $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]);
687
        $table2->addColumn('column_blob', 'blob');
688
689
        // VARBINARY -> BLOB
690
        // BINARY    -> BINARY with changed length
691
        // BLOB      -> BLOB
692
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
693
    }
694
695
    /**
696
     * {@inheritDoc}
697
     *
698
     * @group DBAL-234
699
     */
700
    protected function getAlterTableRenameIndexSQL() : array
701
    {
702
        return ['ALTER INDEX idx_foo RENAME TO idx_bar'];
703
    }
704
705
    /**
706
     * {@inheritDoc}
707
     *
708
     * @group DBAL-234
709
     */
710
    protected function getQuotedAlterTableRenameIndexSQL() : array
711
    {
712
        return [
713
            'ALTER INDEX "create" RENAME TO "select"',
714
            'ALTER INDEX "foo" RENAME TO "bar"',
715
        ];
716
    }
717
718
    /**
719
     * PostgreSQL boolean strings provider
720
     *
721
     * @return mixed[][]
722
     */
723
    public static function pgBooleanProvider() : iterable
724
    {
725
        return [
726
            // Database value, prepared statement value, boolean integer value, boolean value.
727
            ['t', 'true', 1, true],
728
            ['true', 'true', 1, true],
729
            ['y', 'true', 1, true],
730
            ['yes', 'true', 1, true],
731
            ['on', 'true', 1, true],
732
            ['1', 'true', 1, true],
733
734
            ['f', 'false', 0, false],
735
            ['false', 'false', 0, false],
736
            [ 'n', 'false', 0, false],
737
            ['no', 'false', 0, false],
738
            ['off', 'false', 0, false],
739
            ['0', 'false', 0, false],
740
        ];
741
    }
742
743
    /**
744
     * {@inheritdoc}
745
     */
746
    protected function getQuotedAlterTableRenameColumnSQL() : array
747
    {
748
        return [
749
            'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted',
750
            'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"',
751
            'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"',
752
            'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword',
753
            'ALTER TABLE mytable RENAME COLUMN "table" TO "from"',
754
            'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"',
755
            'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted',
756
            'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"',
757
            'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"',
758
        ];
759
    }
760
761
    /**
762
     * {@inheritdoc}
763
     */
764
    protected function getQuotedAlterTableChangeColumnLengthSQL() : array
765
    {
766
        return [
767
            'ALTER TABLE mytable ALTER unquoted1 TYPE VARCHAR(255)',
768
            'ALTER TABLE mytable ALTER unquoted2 TYPE VARCHAR(255)',
769
            'ALTER TABLE mytable ALTER unquoted3 TYPE VARCHAR(255)',
770
            'ALTER TABLE mytable ALTER "create" TYPE VARCHAR(255)',
771
            'ALTER TABLE mytable ALTER "table" TYPE VARCHAR(255)',
772
            'ALTER TABLE mytable ALTER "select" TYPE VARCHAR(255)',
773
        ];
774
    }
775
776
    /**
777
     * {@inheritDoc}
778
     *
779
     * @group DBAL-807
780
     */
781
    protected function getAlterTableRenameIndexInSchemaSQL() : array
782
    {
783
        return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar'];
784
    }
785
786
    /**
787
     * {@inheritDoc}
788
     *
789
     * @group DBAL-807
790
     */
791
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
792
    {
793
        return [
794
            'ALTER INDEX "schema"."create" RENAME TO "select"',
795
            'ALTER INDEX "schema"."foo" RENAME TO "bar"',
796
        ];
797
    }
798
799
    protected function getQuotesDropForeignKeySQL() : string
800
    {
801
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
802
    }
803
804
    /**
805
     * @group DBAL-423
806
     */
807
    public function testReturnsGuidTypeDeclarationSQL() : void
808
    {
809
        self::assertSame('UUID', $this->platform->getGuidTypeDeclarationSQL([]));
810
    }
811
812
    /**
813
     * {@inheritdoc}
814
     */
815
    public function getAlterTableRenameColumnSQL() : array
816
    {
817
        return ['ALTER TABLE foo RENAME COLUMN bar TO baz'];
818
    }
819
820
    /**
821
     * {@inheritdoc}
822
     */
823
    protected function getQuotesTableIdentifiersInAlterTableSQL() : array
824
    {
825
        return [
826
            'ALTER TABLE "foo" DROP CONSTRAINT fk1',
827
            'ALTER TABLE "foo" DROP CONSTRAINT fk2',
828
            'ALTER TABLE "foo" ADD bloo INT NOT NULL',
829
            'ALTER TABLE "foo" DROP baz',
830
            'ALTER TABLE "foo" ALTER bar DROP NOT NULL',
831
            'ALTER TABLE "foo" RENAME COLUMN id TO war',
832
            'ALTER TABLE "foo" RENAME TO "table"',
833
            'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE ' .
834
            'INITIALLY IMMEDIATE',
835
            'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE ' .
836
            'INITIALLY IMMEDIATE',
837
        ];
838
    }
839
840
    /**
841
     * {@inheritdoc}
842
     */
843
    protected function getCommentOnColumnSQL() : array
844
    {
845
        return [
846
            'COMMENT ON COLUMN foo.bar IS \'comment\'',
847
            'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'',
848
            'COMMENT ON COLUMN "select"."from" IS \'comment\'',
849
        ];
850
    }
851
852
    /**
853
     * @group DBAL-1004
854
     */
855
    public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void
856
    {
857
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]);
858
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]);
859
860
        $comparator = new Comparator();
861
862
        $tableDiff = $comparator->diffTable($table1, $table2);
863
864
        self::assertInstanceOf(TableDiff::class, $tableDiff);
865
        self::assertSame(
866
            ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''],
867
            $this->platform->getAlterTableSQL($tableDiff)
868
        );
869
    }
870
871
    /**
872
     * @group 3158
873
     */
874
    public function testAltersTableColumnCommentIfRequiredByType() : void
875
    {
876
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime'))]);
877
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime_immutable'))]);
878
879
        $comparator = new Comparator();
880
881
        $tableDiff = $comparator->diffTable($table1, $table2);
882
883
        $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
884
        $this->assertSame(
885
            [
886
                'ALTER TABLE "foo" ALTER "bar" TYPE TIMESTAMP(0) WITHOUT TIME ZONE',
887
                'ALTER TABLE "foo" ALTER "bar" DROP DEFAULT',
888
                'COMMENT ON COLUMN "foo"."bar" IS \'(DC2Type:datetime_immutable)\'',
889
            ],
890
            $this->platform->getAlterTableSQL($tableDiff)
891
        );
892
    }
893
894
    /**
895
     * {@inheritdoc}
896
     */
897
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
898
    {
899
        return 'CONSTRAINT "select" UNIQUE (foo)';
900
    }
901
902
    /**
903
     * {@inheritdoc}
904
     */
905
    protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
906
    {
907
        return 'INDEX "select" (foo)';
908
    }
909
910
    /**
911
     * {@inheritdoc}
912
     */
913
    protected function getQuotesReservedKeywordInTruncateTableSQL() : string
914
    {
915
        return 'TRUNCATE "select"';
916
    }
917
918
    /**
919
     * {@inheritdoc}
920
     */
921
    protected function getAlterStringToFixedStringSQL() : array
922
    {
923
        return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)'];
924
    }
925
926
    /**
927
     * {@inheritdoc}
928
     */
929
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array
930
    {
931
        return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed'];
932
    }
933
934
    /**
935
     * @group DBAL-1142
936
     */
937
    public function testInitializesTsvectorTypeMapping() : void
938
    {
939
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector'));
940
        self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector'));
941
    }
942
943
    /**
944
     * @group DBAL-1220
945
     */
946
    public function testReturnsDisallowDatabaseConnectionsSQL() : void
947
    {
948
        self::assertSame(
949
            "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'",
950
            $this->platform->getDisallowDatabaseConnectionsSQL('foo')
0 ignored issues
show
Bug introduced by
The method getDisallowDatabaseConnectionsSQL() does not exist on Doctrine\DBAL\Platforms\AbstractPlatform. It seems like you code against a sub-type of Doctrine\DBAL\Platforms\AbstractPlatform such as Doctrine\DBAL\Platforms\PostgreSqlPlatform. ( Ignorable by Annotation )

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

950
            $this->platform->/** @scrutinizer ignore-call */ 
951
                             getDisallowDatabaseConnectionsSQL('foo')
Loading history...
951
        );
952
    }
953
954
    /**
955
     * @group DBAL-1220
956
     */
957
    public function testReturnsCloseActiveDatabaseConnectionsSQL() : void
958
    {
959
        self::assertSame(
960
            "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'",
961
            $this->platform->getCloseActiveDatabaseConnectionsSQL('foo')
0 ignored issues
show
Bug introduced by
The method getCloseActiveDatabaseConnectionsSQL() does not exist on Doctrine\DBAL\Platforms\AbstractPlatform. It seems like you code against a sub-type of Doctrine\DBAL\Platforms\AbstractPlatform such as Doctrine\DBAL\Platforms\PostgreSqlPlatform. ( Ignorable by Annotation )

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

961
            $this->platform->/** @scrutinizer ignore-call */ 
962
                             getCloseActiveDatabaseConnectionsSQL('foo')
Loading history...
962
        );
963
    }
964
965
    /**
966
     * @group DBAL-2436
967
     */
968
    public function testQuotesTableNameInListTableForeignKeysSQL() : void
969
    {
970
        self::assertStringContainsStringIgnoringCase(
971
            "'Foo''Bar\\'",
972
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\")
973
        );
974
    }
975
976
    /**
977
     * @group DBAL-2436
978
     */
979
    public function testQuotesSchemaNameInListTableForeignKeysSQL() : void
980
    {
981
        self::assertStringContainsStringIgnoringCase(
982
            "'Foo''Bar\\'",
983
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table")
984
        );
985
    }
986
987
    /**
988
     * @group DBAL-2436
989
     */
990
    public function testQuotesTableNameInListTableConstraintsSQL() : void
991
    {
992
        self::assertStringContainsStringIgnoringCase(
993
            "'Foo''Bar\\'",
994
            $this->platform->getListTableConstraintsSQL("Foo'Bar\\")
995
        );
996
    }
997
998
    /**
999
     * @group DBAL-2436
1000
     */
1001
    public function testQuotesTableNameInListTableIndexesSQL() : void
1002
    {
1003
        self::assertStringContainsStringIgnoringCase(
1004
            "'Foo''Bar\\'",
1005
            $this->platform->getListTableIndexesSQL("Foo'Bar\\")
1006
        );
1007
    }
1008
1009
    /**
1010
     * @group DBAL-2436
1011
     */
1012
    public function testQuotesSchemaNameInListTableIndexesSQL() : void
1013
    {
1014
        self::assertStringContainsStringIgnoringCase(
1015
            "'Foo''Bar\\'",
1016
            $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table")
1017
        );
1018
    }
1019
1020
    /**
1021
     * @group DBAL-2436
1022
     */
1023
    public function testQuotesTableNameInListTableColumnsSQL() : void
1024
    {
1025
        self::assertStringContainsStringIgnoringCase(
1026
            "'Foo''Bar\\'",
1027
            $this->platform->getListTableColumnsSQL("Foo'Bar\\")
1028
        );
1029
    }
1030
1031
    /**
1032
     * @group DBAL-2436
1033
     */
1034
    public function testQuotesSchemaNameInListTableColumnsSQL() : void
1035
    {
1036
        self::assertStringContainsStringIgnoringCase(
1037
            "'Foo''Bar\\'",
1038
            $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table")
1039
        );
1040
    }
1041
1042
    /**
1043
     * @group DBAL-2436
1044
     */
1045
    public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void
1046
    {
1047
        self::assertStringContainsStringIgnoringCase(
1048
            "'Foo''Bar\\'",
1049
            $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\")
1050
        );
1051
    }
1052
}
1053