Completed
Pull Request — master (#3610)
by Sergei
03:03
created

testConvertBooleanAsLiteralIntegers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
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\Platforms\PostgreSqlPlatform;
8
use Doctrine\DBAL\Schema\Column;
9
use Doctrine\DBAL\Schema\ColumnDiff;
10
use Doctrine\DBAL\Schema\Comparator;
11
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
12
use Doctrine\DBAL\Schema\Sequence;
13
use Doctrine\DBAL\Schema\Table;
14
use Doctrine\DBAL\Schema\TableDiff;
15
use Doctrine\DBAL\TransactionIsolationLevel;
16
use Doctrine\DBAL\Types\Type;
17
use UnexpectedValueException;
18
use function assert;
19
use function sprintf;
20
21
abstract class AbstractPostgreSqlPlatformTestCase extends AbstractPlatformTestCase
22
{
23
    /** @var PostgreSqlPlatform */
24
    protected $platform;
25
26
    public function getGenerateTableSql() : string
27
    {
28
        return 'CREATE TABLE test (id SERIAL NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
29
    }
30
31
    /**
32
     * {@inheritDoc}
33
     */
34
    public function getGenerateTableWithMultiColumnUniqueIndexSql() : array
35
    {
36
        return [
37
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
38
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
39
        ];
40
    }
41
42
    /**
43
     * {@inheritDoc}
44
     */
45
    public function getGenerateAlterTableSql() : array
46
    {
47
        return [
48
            'ALTER TABLE mytable ADD quota INT DEFAULT NULL',
49
            'ALTER TABLE mytable DROP foo',
50
            'ALTER TABLE mytable ALTER bar TYPE VARCHAR(255)',
51
            "ALTER TABLE mytable ALTER bar SET DEFAULT 'def'",
52
            'ALTER TABLE mytable ALTER bar SET NOT NULL',
53
            'ALTER TABLE mytable ALTER bloo TYPE BOOLEAN',
54
            "ALTER TABLE mytable ALTER bloo SET DEFAULT 'false'",
55
            'ALTER TABLE mytable ALTER bloo SET NOT NULL',
56
            'ALTER TABLE mytable RENAME TO userlist',
57
        ];
58
    }
59
60
    public function getGenerateIndexSql() : string
61
    {
62
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
63
    }
64
65
    public function getGenerateForeignKeySql() : string
66
    {
67
        return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE';
68
    }
69
70
    public function testGeneratesForeignKeySqlForNonStandardOptions() : void
71
    {
72
        $foreignKey = new ForeignKeyConstraint(
73
            ['foreign_id'],
74
            'my_table',
75
            ['id'],
76
            'my_fk',
77
            ['onDelete' => 'CASCADE']
78
        );
79
        self::assertEquals(
80
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE',
81
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
82
        );
83
84
        $foreignKey = new ForeignKeyConstraint(
85
            ['foreign_id'],
86
            'my_table',
87
            ['id'],
88
            'my_fk',
89
            ['match' => 'full']
90
        );
91
        self::assertEquals(
92
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full NOT DEFERRABLE INITIALLY IMMEDIATE',
93
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
94
        );
95
96
        $foreignKey = new ForeignKeyConstraint(
97
            ['foreign_id'],
98
            'my_table',
99
            ['id'],
100
            'my_fk',
101
            ['deferrable' => true]
102
        );
103
        self::assertEquals(
104
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) DEFERRABLE INITIALLY IMMEDIATE',
105
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
106
        );
107
108
        $foreignKey = new ForeignKeyConstraint(
109
            ['foreign_id'],
110
            'my_table',
111
            ['id'],
112
            'my_fk',
113
            ['deferred' => true]
114
        );
115
        self::assertEquals(
116
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
117
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
118
        );
119
120
        $foreignKey = new ForeignKeyConstraint(
121
            ['foreign_id'],
122
            'my_table',
123
            ['id'],
124
            'my_fk',
125
            ['deferred' => true]
126
        );
127
        self::assertEquals(
128
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
129
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
130
        );
131
132
        $foreignKey = new ForeignKeyConstraint(
133
            ['foreign_id'],
134
            'my_table',
135
            ['id'],
136
            'my_fk',
137
            ['deferrable' => true, 'deferred' => true, 'match' => 'full']
138
        );
139
        self::assertEquals(
140
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full DEFERRABLE INITIALLY DEFERRED',
141
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
142
        );
143
    }
144
145
    public function testGeneratesSqlSnippets() : void
146
    {
147
        self::assertEquals('SIMILAR TO', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct');
148
        self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct');
149
        self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct');
150
        self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct');
151
        self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', '1', '5'), 'Substring expression with length is not correct');
152
    }
153
154 View Code Duplication
    public function testGeneratesTransactionCommands() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
    {
156
        self::assertEquals(
157
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
158
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED)
159
        );
160
        self::assertEquals(
161
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED',
162
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED)
163
        );
164
        self::assertEquals(
165
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ',
166
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ)
167
        );
168
        self::assertEquals(
169
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE',
170
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE)
171
        );
172
    }
173
174
    public function testGeneratesDDLSnippets() : void
175
    {
176
        self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar'));
177
        self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar'));
178
        self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar'));
179
    }
180
181 View Code Duplication
    public function testGenerateTableWithAutoincrement() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
182
    {
183
        $table  = new Table('autoinc_table');
184
        $column = $table->addColumn('id', 'integer');
185
        $column->setAutoincrement(true);
186
187
        self::assertEquals(['CREATE TABLE autoinc_table (id SERIAL NOT NULL)'], $this->platform->getCreateTableSQL($table));
188
    }
189
190
    /**
191
     * @return mixed[][]
192
     */
193
    public static function serialTypes() : iterable
194
    {
195
        return [
196
            ['integer', 'SERIAL'],
197
            ['bigint', 'BIGSERIAL'],
198
        ];
199
    }
200
201
    /**
202
     * @dataProvider serialTypes
203
     * @group 2906
204
     */
205 View Code Duplication
    public function testGenerateTableWithAutoincrementDoesNotSetDefault(string $type, string $definition) : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
206
    {
207
        $table  = new Table('autoinc_table_notnull');
208
        $column = $table->addColumn('id', $type);
209
        $column->setAutoIncrement(true);
210
        $column->setNotNull(false);
211
212
        $sql = $this->platform->getCreateTableSQL($table);
213
214
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull (id %s)', $definition)], $sql);
215
    }
216
217
    /**
218
     * @dataProvider serialTypes
219
     * @group 2906
220
     */
221 View Code Duplication
    public function testCreateTableWithAutoincrementAndNotNullAddsConstraint(string $type, string $definition) : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
    {
223
        $table  = new Table('autoinc_table_notnull_enabled');
224
        $column = $table->addColumn('id', $type);
225
        $column->setAutoIncrement(true);
226
        $column->setNotNull(true);
227
228
        $sql = $this->platform->getCreateTableSQL($table);
229
230
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull_enabled (id %s NOT NULL)', $definition)], $sql);
231
    }
232
233
    /**
234
     * @dataProvider serialTypes
235
     * @group 2906
236
     */
237
    public function testGetDefaultValueDeclarationSQLIgnoresTheDefaultKeyWhenTheFieldIsSerial(string $type) : void
238
    {
239
        $sql = $this->platform->getDefaultValueDeclarationSQL(
240
            [
241
                'autoincrement' => true,
242
                'type'          => Type::getType($type),
243
                'default'       => 1,
244
            ]
245
        );
246
247
        self::assertSame('', $sql);
248
    }
249
250 View Code Duplication
    public function testGeneratesTypeDeclarationForIntegers() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
    {
252
        self::assertEquals(
253
            'INT',
254
            $this->platform->getIntegerTypeDeclarationSQL([])
255
        );
256
        self::assertEquals(
257
            'SERIAL',
258
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true])
259
        );
260
        self::assertEquals(
261
            'SERIAL',
262
            $this->platform->getIntegerTypeDeclarationSQL(
263
                ['autoincrement' => true, 'primary' => true]
264
            )
265
        );
266
    }
267
268
    public function getGenerateUniqueIndexSql() : string
269
    {
270
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
271
    }
272
273
    public function testGeneratesSequenceSqlCommands() : void
274
    {
275
        $sequence = new Sequence('myseq', 20, 1);
276
        self::assertEquals(
277
            'CREATE SEQUENCE myseq INCREMENT BY 20 MINVALUE 1 START 1',
278
            $this->platform->getCreateSequenceSQL($sequence)
279
        );
280
        self::assertEquals(
281
            'DROP SEQUENCE myseq CASCADE',
282
            $this->platform->getDropSequenceSQL('myseq')
283
        );
284
        self::assertEquals(
285
            "SELECT NEXTVAL('myseq')",
286
            $this->platform->getSequenceNextValSQL('myseq')
287
        );
288
    }
289
290
    public function testDoesNotPreferIdentityColumns() : void
291
    {
292
        self::assertFalse($this->platform->prefersIdentityColumns());
293
    }
294
295
    public function testPrefersSequences() : void
296
    {
297
        self::assertTrue($this->platform->prefersSequences());
298
    }
299
300
    public function testSupportsIdentityColumns() : void
301
    {
302
        self::assertTrue($this->platform->supportsIdentityColumns());
303
    }
304
305
    public function testSupportsSavePoints() : void
306
    {
307
        self::assertTrue($this->platform->supportsSavepoints());
308
    }
309
310
    public function testSupportsSequences() : void
311
    {
312
        self::assertTrue($this->platform->supportsSequences());
313
    }
314
315
    /**
316
     * {@inheritdoc}
317
     */
318
    protected function supportsCommentOnStatement() : bool
319
    {
320
        return true;
321
    }
322
323
    public function testModifyLimitQuery() : void
324
    {
325
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
326
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
327
    }
328
329
    public function testModifyLimitQueryWithEmptyOffset() : void
330
    {
331
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
332
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
333
    }
334
335
    /**
336
     * {@inheritDoc}
337
     */
338
    public function getCreateTableColumnCommentsSQL() : array
339
    {
340
        return [
341
            'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))',
342
            "COMMENT ON COLUMN test.id IS 'This is a comment'",
343
        ];
344
    }
345
346
    /**
347
     * {@inheritDoc}
348
     */
349
    public function getAlterTableColumnCommentsSQL() : array
350
    {
351
        return [
352
            'ALTER TABLE mytable ADD quota INT NOT NULL',
353
            "COMMENT ON COLUMN mytable.quota IS 'A comment'",
354
            'COMMENT ON COLUMN mytable.foo IS NULL',
355
            "COMMENT ON COLUMN mytable.baz IS 'B comment'",
356
        ];
357
    }
358
359
    /**
360
     * {@inheritDoc}
361
     */
362
    public function getCreateTableColumnTypeCommentsSQL() : array
363
    {
364
        return [
365
            'CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))',
366
            "COMMENT ON COLUMN test.data IS '(DC2Type:array)'",
367
        ];
368
    }
369
370
    /**
371
     * {@inheritDoc}
372
     */
373
    protected function getQuotedColumnInPrimaryKeySQL() : array
374
    {
375
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
376
    }
377
378
    /**
379
     * {@inheritDoc}
380
     */
381
    protected function getQuotedColumnInIndexSQL() : array
382
    {
383
        return [
384
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
385
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
386
        ];
387
    }
388
389
    /**
390
     * {@inheritDoc}
391
     */
392
    protected function getQuotedNameInIndexSQL() : array
393
    {
394
        return [
395
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
396
            'CREATE INDEX "key" ON test (column1)',
397
        ];
398
    }
399
400
    /**
401
     * {@inheritDoc}
402
     */
403
    protected function getQuotedColumnInForeignKeySQL() : array
404
    {
405
        return [
406
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
407
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
408
            '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',
409
            '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',
410
        ];
411
    }
412
413
    /**
414
     * @group DBAL-457
415
     * @dataProvider pgBooleanProvider
416
     */
417
    public function testConvertBooleanAsLiteralStrings(
418
        string $databaseValue,
419
        string $preparedStatementValue,
420
        int $integerValue,
0 ignored issues
show
Unused Code introduced by
The parameter $integerValue is not used and could be removed.

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

Loading history...
421
        bool $booleanValue
0 ignored issues
show
Unused Code introduced by
The parameter $booleanValue is not used and could be removed.

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

Loading history...
422
    ) : void {
423
        self::assertEquals($preparedStatementValue, $this->platform->convertBooleans($databaseValue));
424
    }
425
426
    /**
427
     * @group DBAL-457
428
     */
429
    public function testConvertBooleanAsLiteralIntegers() : void
430
    {
431
        $this->platform->setUseBooleanTrueFalseStrings(false);
432
433
        self::assertEquals(1, $this->platform->convertBooleans(true));
434
        self::assertEquals(1, $this->platform->convertBooleans('1'));
435
436
        self::assertEquals(0, $this->platform->convertBooleans(false));
437
        self::assertEquals(0, $this->platform->convertBooleans('0'));
438
    }
439
440
    /**
441
     * @group DBAL-630
442
     * @dataProvider pgBooleanProvider
443
     */
444
    public function testConvertBooleanAsDatabaseValueStrings(
445
        string $databaseValue,
0 ignored issues
show
Unused Code introduced by
The parameter $databaseValue is not used and could be removed.

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

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

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

Loading history...
447
        int $integerValue,
448
        bool $booleanValue
449
    ) : void {
450
        self::assertSame($integerValue, $this->platform->convertBooleansToDatabaseValue($booleanValue));
451
    }
452
453
    /**
454
     * @group DBAL-630
455
     */
456
    public function testConvertBooleanAsDatabaseValueIntegers() : void
457
    {
458
        $this->platform->setUseBooleanTrueFalseStrings(false);
459
460
        self::assertSame(1, $this->platform->convertBooleansToDatabaseValue(true));
461
        self::assertSame(0, $this->platform->convertBooleansToDatabaseValue(false));
462
    }
463
464
    /**
465
     * @dataProvider pgBooleanProvider
466
     */
467
    public function testConvertFromBoolean(string $databaseValue, string $prepareStatementValue, int $integerValue, bool $booleanValue) : void
0 ignored issues
show
Unused Code introduced by
The parameter $prepareStatementValue is not used and could be removed.

This check looks from 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 $integerValue is not used and could be removed.

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

Loading history...
468
    {
469
        self::assertSame($booleanValue, $this->platform->convertFromBoolean($databaseValue));
470
    }
471
472
    public function testThrowsExceptionWithInvalidBooleanLiteral() : void
473
    {
474
        $this->expectException(UnexpectedValueException::class);
475
        $this->expectExceptionMessage('Unrecognized boolean literal, my-bool given.');
476
477
        $this->platform->convertBooleansToDatabaseValue('my-bool');
478
    }
479
480
    public function testGetCreateSchemaSQL() : void
481
    {
482
        $schemaName = 'schema';
483
        $sql        = $this->platform->getCreateSchemaSQL($schemaName);
484
        self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql);
485
    }
486
487
    public function testAlterDecimalPrecisionScale() : void
488
    {
489
        $table = new Table('mytable');
490
        $table->addColumn('dfoo1', 'decimal');
491
        $table->addColumn('dfoo2', 'decimal', ['precision' => 10, 'scale' => 6]);
492
        $table->addColumn('dfoo3', 'decimal', ['precision' => 10, 'scale' => 6]);
493
        $table->addColumn('dfoo4', 'decimal', ['precision' => 10, 'scale' => 6]);
494
495
        $tableDiff            = new TableDiff('mytable');
496
        $tableDiff->fromTable = $table;
497
498
        $tableDiff->changedColumns['dloo1'] = new ColumnDiff(
499
            'dloo1',
500
            new Column(
501
                'dloo1',
502
                Type::getType('decimal'),
503
                ['precision' => 16, 'scale' => 6]
504
            ),
505
            ['precision']
506
        );
507
        $tableDiff->changedColumns['dloo2'] = new ColumnDiff(
508
            'dloo2',
509
            new Column(
510
                'dloo2',
511
                Type::getType('decimal'),
512
                ['precision' => 10, 'scale' => 4]
513
            ),
514
            ['scale']
515
        );
516
        $tableDiff->changedColumns['dloo3'] = new ColumnDiff(
517
            'dloo3',
518
            new Column(
519
                'dloo3',
520
                Type::getType('decimal'),
521
                ['precision' => 10, 'scale' => 6]
522
            ),
523
            []
524
        );
525
        $tableDiff->changedColumns['dloo4'] = new ColumnDiff(
526
            'dloo4',
527
            new Column(
528
                'dloo4',
529
                Type::getType('decimal'),
530
                ['precision' => 16, 'scale' => 8]
531
            ),
532
            ['precision', 'scale']
533
        );
534
535
        $sql = $this->platform->getAlterTableSQL($tableDiff);
536
537
        $expectedSql = [
538
            'ALTER TABLE mytable ALTER dloo1 TYPE NUMERIC(16, 6)',
539
            'ALTER TABLE mytable ALTER dloo2 TYPE NUMERIC(10, 4)',
540
            'ALTER TABLE mytable ALTER dloo4 TYPE NUMERIC(16, 8)',
541
        ];
542
543
        self::assertEquals($expectedSql, $sql);
544
    }
545
546
    /**
547
     * @group DBAL-365
548
     */
549
    public function testDroppingConstraintsBeforeColumns() : void
550
    {
551
        $newTable = new Table('mytable');
552
        $newTable->addColumn('id', 'integer');
553
        $newTable->setPrimaryKey(['id']);
554
555
        $oldTable = clone $newTable;
556
        $oldTable->addColumn('parent_id', 'integer');
557
        $oldTable->addForeignKeyConstraint('mytable', ['parent_id'], ['id']);
558
559
        $comparator = new Comparator();
560
        $tableDiff  = $comparator->diffTable($oldTable, $newTable);
561
562
        self::assertNotNull($tableDiff);
563
564
        $sql = $this->platform->getAlterTableSQL($tableDiff);
0 ignored issues
show
Bug introduced by
It seems like $tableDiff defined by $comparator->diffTable($oldTable, $newTable) on line 560 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
565
566
        $expectedSql = [
567
            'ALTER TABLE mytable DROP CONSTRAINT FK_6B2BD609727ACA70',
568
            'DROP INDEX IDX_6B2BD609727ACA70',
569
            'ALTER TABLE mytable DROP parent_id',
570
        ];
571
572
        self::assertEquals($expectedSql, $sql);
573
    }
574
575
    /**
576
     * @group DBAL-563
577
     */
578
    public function testUsesSequenceEmulatedIdentityColumns() : void
579
    {
580
        self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns());
581
    }
582
583
    /**
584
     * @group DBAL-563
585
     */
586
    public function testReturnsIdentitySequenceName() : void
587
    {
588
        self::assertSame('mytable_mycolumn_seq', $this->platform->getIdentitySequenceName('mytable', 'mycolumn'));
589
    }
590
591
    /**
592
     * @dataProvider dataCreateSequenceWithCache
593
     * @group DBAL-139
594
     */
595
    public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void
596
    {
597
        $sequence = new Sequence('foo', 1, 1, $cacheSize);
598
        self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence));
599
    }
600
601
    /**
602
     * @return mixed[][]
603
     */
604
    public static function dataCreateSequenceWithCache() : iterable
605
    {
606
        return [
607
            [3, 'CACHE 3'],
608
        ];
609
    }
610
611
    public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string
612
    {
613
        return 'BYTEA';
614
    }
615
616
    public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string
617
    {
618
        return 'BYTEA';
619
    }
620
621
    public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string
622
    {
623
        return 'BYTEA';
624
    }
625
626
    public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string
627
    {
628
        return 'BYTEA';
629
    }
630
631
    public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void
632
    {
633
        $table1 = new Table('mytable');
634
        $table1->addColumn('column_varbinary', 'binary');
635
        $table1->addColumn('column_binary', 'binary', ['fixed' => true]);
636
        $table1->addColumn('column_blob', 'blob');
637
638
        $table2 = new Table('mytable');
639
        $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]);
640
        $table2->addColumn('column_binary', 'binary');
641
        $table2->addColumn('column_blob', 'binary');
642
643
        $comparator = new Comparator();
644
645
        $diff = $comparator->diffTable($table1, $table2);
646
647
        self::assertNotNull($diff);
648
649
        // VARBINARY -> BINARY
650
        // BINARY    -> VARBINARY
651
        // BLOB      -> VARBINARY
652
        self::assertEmpty($this->platform->getAlterTableSQL($diff));
0 ignored issues
show
Bug introduced by
It seems like $diff defined by $comparator->diffTable($table1, $table2) on line 645 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
653
654
        $table2 = new Table('mytable');
655
        $table2->addColumn('column_varbinary', 'binary', ['length' => 42]);
656
        $table2->addColumn('column_binary', 'blob');
657
        $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]);
658
659
        $diff = $comparator->diffTable($table1, $table2);
660
661
        self::assertNotNull($diff);
662
663
        // VARBINARY -> VARBINARY with changed length
664
        // BINARY    -> BLOB
665
        // BLOB      -> BINARY
666
        self::assertEmpty($this->platform->getAlterTableSQL($diff));
0 ignored issues
show
Bug introduced by
It seems like $diff defined by $comparator->diffTable($table1, $table2) on line 659 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
667
668
        $table2 = new Table('mytable');
669
        $table2->addColumn('column_varbinary', 'blob');
670
        $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]);
671
        $table2->addColumn('column_blob', 'blob');
672
673
        $diff = $comparator->diffTable($table1, $table2);
674
675
        self::assertNotNull($diff);
676
677
        // VARBINARY -> BLOB
678
        // BINARY    -> BINARY with changed length
679
        // BLOB      -> BLOB
680
        self::assertEmpty($this->platform->getAlterTableSQL($diff));
0 ignored issues
show
Bug introduced by
It seems like $diff defined by $comparator->diffTable($table1, $table2) on line 673 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
681
    }
682
683
    /**
684
     * {@inheritDoc}
685
     *
686
     * @group DBAL-234
687
     */
688
    protected function getAlterTableRenameIndexSQL() : array
689
    {
690
        return ['ALTER INDEX idx_foo RENAME TO idx_bar'];
691
    }
692
693
    /**
694
     * {@inheritDoc}
695
     *
696
     * @group DBAL-234
697
     */
698
    protected function getQuotedAlterTableRenameIndexSQL() : array
699
    {
700
        return [
701
            'ALTER INDEX "create" RENAME TO "select"',
702
            'ALTER INDEX "foo" RENAME TO "bar"',
703
        ];
704
    }
705
706
    /**
707
     * PostgreSQL boolean strings provider
708
     *
709
     * @return mixed[][]
710
     */
711
    public static function pgBooleanProvider() : iterable
712
    {
713
        return [
714
            // Database value, prepared statement value, boolean integer value, boolean value.
715
            ['t', 'true', 1, true],
716
            ['true', 'true', 1, true],
717
            ['y', 'true', 1, true],
718
            ['yes', 'true', 1, true],
719
            ['on', 'true', 1, true],
720
            ['1', 'true', 1, true],
721
722
            ['f', 'false', 0, false],
723
            ['false', 'false', 0, false],
724
            [ 'n', 'false', 0, false],
725
            ['no', 'false', 0, false],
726
            ['off', 'false', 0, false],
727
            ['0', 'false', 0, false],
728
        ];
729
    }
730
731
    /**
732
     * {@inheritdoc}
733
     */
734
    protected function getQuotedAlterTableRenameColumnSQL() : array
735
    {
736
        return [
737
            'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted',
738
            'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"',
739
            'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"',
740
            'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword',
741
            'ALTER TABLE mytable RENAME COLUMN "table" TO "from"',
742
            'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"',
743
            'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted',
744
            'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"',
745
            'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"',
746
        ];
747
    }
748
749
    /**
750
     * {@inheritdoc}
751
     */
752
    protected function getQuotedAlterTableChangeColumnLengthSQL() : array
753
    {
754
        return [
755
            'ALTER TABLE mytable ALTER unquoted1 TYPE VARCHAR(255)',
756
            'ALTER TABLE mytable ALTER unquoted2 TYPE VARCHAR(255)',
757
            'ALTER TABLE mytable ALTER unquoted3 TYPE VARCHAR(255)',
758
            'ALTER TABLE mytable ALTER "create" TYPE VARCHAR(255)',
759
            'ALTER TABLE mytable ALTER "table" TYPE VARCHAR(255)',
760
            'ALTER TABLE mytable ALTER "select" TYPE VARCHAR(255)',
761
        ];
762
    }
763
764
    /**
765
     * {@inheritDoc}
766
     *
767
     * @group DBAL-807
768
     */
769
    protected function getAlterTableRenameIndexInSchemaSQL() : array
770
    {
771
        return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar'];
772
    }
773
774
    /**
775
     * {@inheritDoc}
776
     *
777
     * @group DBAL-807
778
     */
779
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
780
    {
781
        return [
782
            'ALTER INDEX "schema"."create" RENAME TO "select"',
783
            'ALTER INDEX "schema"."foo" RENAME TO "bar"',
784
        ];
785
    }
786
787
    protected function getQuotesDropForeignKeySQL() : string
788
    {
789
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
790
    }
791
792
    /**
793
     * @group DBAL-423
794
     */
795
    public function testReturnsGuidTypeDeclarationSQL() : void
796
    {
797
        self::assertSame('UUID', $this->platform->getGuidTypeDeclarationSQL([]));
798
    }
799
800
    /**
801
     * {@inheritdoc}
802
     */
803
    public function getAlterTableRenameColumnSQL() : array
804
    {
805
        return ['ALTER TABLE foo RENAME COLUMN bar TO baz'];
806
    }
807
808
    /**
809
     * {@inheritdoc}
810
     */
811 View Code Duplication
    protected function getQuotesTableIdentifiersInAlterTableSQL() : array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
812
    {
813
        return [
814
            'ALTER TABLE "foo" DROP CONSTRAINT fk1',
815
            'ALTER TABLE "foo" DROP CONSTRAINT fk2',
816
            'ALTER TABLE "foo" ADD bloo INT NOT NULL',
817
            'ALTER TABLE "foo" DROP baz',
818
            'ALTER TABLE "foo" ALTER bar DROP NOT NULL',
819
            'ALTER TABLE "foo" RENAME COLUMN id TO war',
820
            'ALTER TABLE "foo" RENAME TO "table"',
821
            'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE ' .
822
            'INITIALLY IMMEDIATE',
823
            'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE ' .
824
            'INITIALLY IMMEDIATE',
825
        ];
826
    }
827
828
    /**
829
     * {@inheritdoc}
830
     */
831
    protected function getCommentOnColumnSQL() : array
832
    {
833
        return [
834
            'COMMENT ON COLUMN foo.bar IS \'comment\'',
835
            'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'',
836
            'COMMENT ON COLUMN "select"."from" IS \'comment\'',
837
        ];
838
    }
839
840
    /**
841
     * @group DBAL-1004
842
     */
843
    public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void
844
    {
845
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]);
846
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]);
847
848
        $comparator = new Comparator();
849
850
        $tableDiff = $comparator->diffTable($table1, $table2);
851
852
        self::assertInstanceOf(TableDiff::class, $tableDiff);
853
        self::assertSame(
854
            ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''],
855
            $this->platform->getAlterTableSQL($tableDiff)
0 ignored issues
show
Bug introduced by
It seems like $tableDiff defined by $comparator->diffTable($table1, $table2) on line 850 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
856
        );
857
    }
858
859
    /**
860
     * @group 3158
861
     */
862
    public function testAltersTableColumnCommentIfRequiredByType() : void
863
    {
864
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime'))]);
865
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime_immutable'))]);
866
867
        $comparator = new Comparator();
868
869
        $tableDiff = $comparator->diffTable($table1, $table2);
870
871
        $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
872
        $this->assertSame(
873
            [
874
                'ALTER TABLE "foo" ALTER "bar" TYPE TIMESTAMP(0) WITHOUT TIME ZONE',
875
                'ALTER TABLE "foo" ALTER "bar" DROP DEFAULT',
876
                'COMMENT ON COLUMN "foo"."bar" IS \'(DC2Type:datetime_immutable)\'',
877
            ],
878
            $this->platform->getAlterTableSQL($tableDiff)
0 ignored issues
show
Bug introduced by
It seems like $tableDiff defined by $comparator->diffTable($table1, $table2) on line 869 can be null; however, Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
879
        );
880
    }
881
882
    /**
883
     * {@inheritdoc}
884
     */
885
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
886
    {
887
        return 'CONSTRAINT "select" UNIQUE (foo)';
888
    }
889
890
    /**
891
     * {@inheritdoc}
892
     */
893
    protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
894
    {
895
        return 'INDEX "select" (foo)';
896
    }
897
898
    /**
899
     * {@inheritdoc}
900
     */
901
    protected function getQuotesReservedKeywordInTruncateTableSQL() : string
902
    {
903
        return 'TRUNCATE "select"';
904
    }
905
906
    /**
907
     * {@inheritdoc}
908
     */
909
    protected function getAlterStringToFixedStringSQL() : array
910
    {
911
        return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)'];
912
    }
913
914
    /**
915
     * {@inheritdoc}
916
     */
917
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array
918
    {
919
        return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed'];
920
    }
921
922
    /**
923
     * @group DBAL-1142
924
     */
925
    public function testInitializesTsvectorTypeMapping() : void
926
    {
927
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector'));
928
        self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector'));
929
    }
930
931
    /**
932
     * @group DBAL-1220
933
     */
934
    public function testReturnsDisallowDatabaseConnectionsSQL() : void
935
    {
936
        assert($this->platform instanceof PostgreSqlPlatform);
937
938
        self::assertSame(
939
            "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'",
940
            $this->platform->getDisallowDatabaseConnectionsSQL('foo')
941
        );
942
    }
943
944
    /**
945
     * @group DBAL-1220
946
     */
947
    public function testReturnsCloseActiveDatabaseConnectionsSQL() : void
948
    {
949
        assert($this->platform instanceof PostgreSqlPlatform);
950
951
        self::assertSame(
952
            "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'",
953
            $this->platform->getCloseActiveDatabaseConnectionsSQL('foo')
954
        );
955
    }
956
957
    /**
958
     * @group DBAL-2436
959
     */
960
    public function testQuotesTableNameInListTableForeignKeysSQL() : void
961
    {
962
        self::assertStringContainsStringIgnoringCase(
963
            "'Foo''Bar\\'",
964
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\")
965
        );
966
    }
967
968
    /**
969
     * @group DBAL-2436
970
     */
971
    public function testQuotesSchemaNameInListTableForeignKeysSQL() : void
972
    {
973
        self::assertStringContainsStringIgnoringCase(
974
            "'Foo''Bar\\'",
975
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table")
976
        );
977
    }
978
979
    /**
980
     * @group DBAL-2436
981
     */
982
    public function testQuotesTableNameInListTableConstraintsSQL() : void
983
    {
984
        self::assertStringContainsStringIgnoringCase(
985
            "'Foo''Bar\\'",
986
            $this->platform->getListTableConstraintsSQL("Foo'Bar\\")
987
        );
988
    }
989
990
    /**
991
     * @group DBAL-2436
992
     */
993
    public function testQuotesTableNameInListTableIndexesSQL() : void
994
    {
995
        self::assertStringContainsStringIgnoringCase(
996
            "'Foo''Bar\\'",
997
            $this->platform->getListTableIndexesSQL("Foo'Bar\\")
998
        );
999
    }
1000
1001
    /**
1002
     * @group DBAL-2436
1003
     */
1004
    public function testQuotesSchemaNameInListTableIndexesSQL() : void
1005
    {
1006
        self::assertStringContainsStringIgnoringCase(
1007
            "'Foo''Bar\\'",
1008
            $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table")
1009
        );
1010
    }
1011
1012
    /**
1013
     * @group DBAL-2436
1014
     */
1015
    public function testQuotesTableNameInListTableColumnsSQL() : void
1016
    {
1017
        self::assertStringContainsStringIgnoringCase(
1018
            "'Foo''Bar\\'",
1019
            $this->platform->getListTableColumnsSQL("Foo'Bar\\")
1020
        );
1021
    }
1022
1023
    /**
1024
     * @group DBAL-2436
1025
     */
1026
    public function testQuotesSchemaNameInListTableColumnsSQL() : void
1027
    {
1028
        self::assertStringContainsStringIgnoringCase(
1029
            "'Foo''Bar\\'",
1030
            $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table")
1031
        );
1032
    }
1033
1034
    /**
1035
     * @group DBAL-2436
1036
     */
1037
    public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void
1038
    {
1039
        assert($this->platform instanceof PostgreSqlPlatform);
1040
1041
        self::assertStringContainsStringIgnoringCase(
1042
            "'Foo''Bar\\'",
1043
            $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\")
1044
        );
1045
    }
1046
}
1047