AbstractPostgreSqlPlatformTestCase.php 33.6 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Platforms;

5
use Doctrine\DBAL\Schema\Column;
Sergei Morozov's avatar
Sergei Morozov committed
6
use Doctrine\DBAL\Schema\ColumnDiff;
7
use Doctrine\DBAL\Schema\Comparator;
Sergei Morozov's avatar
Sergei Morozov committed
8 9
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Sequence;
10 11
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
12
use Doctrine\DBAL\TransactionIsolationLevel;
13
use Doctrine\DBAL\Types\Type;
14
use UnexpectedValueException;
Sergei Morozov's avatar
Sergei Morozov committed
15
use function sprintf;
16 17 18

abstract class AbstractPostgreSqlPlatformTestCase extends AbstractPlatformTestCase
{
19
    public function getGenerateTableSql() : string
20 21 22 23
    {
        return 'CREATE TABLE test (id SERIAL NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
    }

24 25 26 27
    /**
     * {@inheritDoc}
     */
    public function getGenerateTableWithMultiColumnUniqueIndexSql() : array
28
    {
Sergei Morozov's avatar
Sergei Morozov committed
29
        return [
30
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
Sergei Morozov's avatar
Sergei Morozov committed
31 32
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
        ];
33 34
    }

35 36 37 38
    /**
     * {@inheritDoc}
     */
    public function getGenerateAlterTableSql() : array
39
    {
Sergei Morozov's avatar
Sergei Morozov committed
40
        return [
41 42 43 44 45 46 47 48 49
            'ALTER TABLE mytable ADD quota INT DEFAULT NULL',
            'ALTER TABLE mytable DROP foo',
            'ALTER TABLE mytable ALTER bar TYPE VARCHAR(255)',
            "ALTER TABLE mytable ALTER bar SET DEFAULT 'def'",
            'ALTER TABLE mytable ALTER bar SET NOT NULL',
            'ALTER TABLE mytable ALTER bloo TYPE BOOLEAN',
            "ALTER TABLE mytable ALTER bloo SET DEFAULT 'false'",
            'ALTER TABLE mytable ALTER bloo SET NOT NULL',
            'ALTER TABLE mytable RENAME TO userlist',
Sergei Morozov's avatar
Sergei Morozov committed
50
        ];
51 52
    }

53
    public function getGenerateIndexSql() : string
54 55 56 57
    {
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
    }

58
    public function getGenerateForeignKeySql() : string
59 60 61 62
    {
        return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE';
    }

63
    public function testGeneratesForeignKeySqlForNonStandardOptions() : void
64
    {
Sergei Morozov's avatar
Sergei Morozov committed
65 66 67 68 69 70
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['onDelete' => 'CASCADE']
71
        );
72
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
73
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE',
Sergei Morozov's avatar
Sergei Morozov committed
74
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
75 76
        );

Sergei Morozov's avatar
Sergei Morozov committed
77 78 79 80 81 82
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['match' => 'full']
83
        );
84
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
85
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full NOT DEFERRABLE INITIALLY IMMEDIATE',
Sergei Morozov's avatar
Sergei Morozov committed
86
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
87 88
        );

Sergei Morozov's avatar
Sergei Morozov committed
89 90 91 92 93 94
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['deferrable' => true]
95
        );
96
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
97
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) DEFERRABLE INITIALLY IMMEDIATE',
Sergei Morozov's avatar
Sergei Morozov committed
98
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
99 100
        );

Sergei Morozov's avatar
Sergei Morozov committed
101 102 103 104 105 106
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['deferred' => true]
107
        );
108
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
109
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
Sergei Morozov's avatar
Sergei Morozov committed
110
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
111 112
        );

Sergei Morozov's avatar
Sergei Morozov committed
113 114 115 116 117 118
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['feferred' => true]
119
        );
120
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
121
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED',
Sergei Morozov's avatar
Sergei Morozov committed
122
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
123 124
        );

Sergei Morozov's avatar
Sergei Morozov committed
125 126 127 128 129 130
        $foreignKey = new ForeignKeyConstraint(
            ['foreign_id'],
            'my_table',
            ['id'],
            'my_fk',
            ['deferrable' => true, 'deferred' => true, 'match' => 'full']
131
        );
132
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
133
            'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full DEFERRABLE INITIALLY DEFERRED',
Sergei Morozov's avatar
Sergei Morozov committed
134
            $this->platform->getForeignKeyDeclarationSQL($foreignKey)
135 136 137
        );
    }

138
    public function testGeneratesSqlSnippets() : void
139
    {
Sergei Morozov's avatar
Sergei Morozov committed
140 141 142 143 144
        self::assertEquals('SIMILAR TO', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct');
        self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct');
        self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct');
        self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct');
        self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', 1, 5), 'Substring expression with length is not correct');
145 146
    }

147
    public function testGeneratesTransactionCommands() : void
148
    {
149
        self::assertEquals(
150
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
Sergei Morozov's avatar
Sergei Morozov committed
151
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED)
152
        );
153
        self::assertEquals(
154
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED',
Sergei Morozov's avatar
Sergei Morozov committed
155
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED)
156
        );
157
        self::assertEquals(
158
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ',
Sergei Morozov's avatar
Sergei Morozov committed
159
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ)
160
        );
161
        self::assertEquals(
162
            'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE',
Sergei Morozov's avatar
Sergei Morozov committed
163
            $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE)
164 165 166
        );
    }

167
    public function testGeneratesDDLSnippets() : void
168
    {
Sergei Morozov's avatar
Sergei Morozov committed
169 170 171
        self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar'));
        self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar'));
        self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar'));
172 173
    }

174
    public function testGenerateTableWithAutoincrement() : void
175
    {
Sergei Morozov's avatar
Sergei Morozov committed
176
        $table  = new Table('autoinc_table');
177 178 179
        $column = $table->addColumn('id', 'integer');
        $column->setAutoincrement(true);

Sergei Morozov's avatar
Sergei Morozov committed
180
        self::assertEquals(['CREATE TABLE autoinc_table (id SERIAL NOT NULL)'], $this->platform->getCreateTableSQL($table));
181 182
    }

Sergei Morozov's avatar
Sergei Morozov committed
183
    /**
184
     * @return mixed[][]
Sergei Morozov's avatar
Sergei Morozov committed
185
     */
186
    public static function serialTypes() : iterable
187 188 189 190 191 192 193 194 195 196 197 198 199
    {
        return [
            ['integer', 'SERIAL'],
            ['bigint', 'BIGSERIAL'],
        ];
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testGenerateTableWithAutoincrementDoesNotSetDefault(string $type, string $definition) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
200
        $table  = new Table('autoinc_table_notnull');
201 202 203 204
        $column = $table->addColumn('id', $type);
        $column->setAutoIncrement(true);
        $column->setNotNull(false);

Sergei Morozov's avatar
Sergei Morozov committed
205
        $sql = $this->platform->getCreateTableSQL($table);
206

Sergei Morozov's avatar
Sergei Morozov committed
207
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull (id %s)', $definition)], $sql);
208 209 210 211 212 213 214 215
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testCreateTableWithAutoincrementAndNotNullAddsConstraint(string $type, string $definition) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
216
        $table  = new Table('autoinc_table_notnull_enabled');
217 218 219 220
        $column = $table->addColumn('id', $type);
        $column->setAutoIncrement(true);
        $column->setNotNull(true);

Sergei Morozov's avatar
Sergei Morozov committed
221
        $sql = $this->platform->getCreateTableSQL($table);
222

Sergei Morozov's avatar
Sergei Morozov committed
223
        self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull_enabled (id %s NOT NULL)', $definition)], $sql);
224 225 226 227 228 229 230 231
    }

    /**
     * @dataProvider serialTypes
     * @group 2906
     */
    public function testGetDefaultValueDeclarationSQLIgnoresTheDefaultKeyWhenTheFieldIsSerial(string $type) : void
    {
Sergei Morozov's avatar
Sergei Morozov committed
232
        $sql = $this->platform->getDefaultValueDeclarationSQL(
233 234 235 236 237 238 239 240 241 242
            [
                'autoincrement' => true,
                'type'          => Type::getType($type),
                'default'       => 1,
            ]
        );

        self::assertSame('', $sql);
    }

243
    public function testGeneratesTypeDeclarationForIntegers() : void
244
    {
245
        self::assertEquals(
246
            'INT',
Sergei Morozov's avatar
Sergei Morozov committed
247
            $this->platform->getIntegerTypeDeclarationSQL([])
248
        );
249
        self::assertEquals(
250
            'SERIAL',
Sergei Morozov's avatar
Sergei Morozov committed
251
            $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true])
Sergei Morozov's avatar
Sergei Morozov committed
252
        );
253
        self::assertEquals(
254
            'SERIAL',
Sergei Morozov's avatar
Sergei Morozov committed
255
            $this->platform->getIntegerTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
256 257 258
                ['autoincrement' => true, 'primary' => true]
            )
        );
259 260
    }

261
    public function testGeneratesTypeDeclarationForStrings() : void
262
    {
263
        self::assertEquals(
264
            'CHAR(10)',
Sergei Morozov's avatar
Sergei Morozov committed
265
            $this->platform->getVarcharTypeDeclarationSQL(
Sergei Morozov's avatar
Sergei Morozov committed
266 267
                ['length' => 10, 'fixed' => true]
            )
268
        );
269
        self::assertEquals(
270
            'VARCHAR(50)',
Sergei Morozov's avatar
Sergei Morozov committed
271
            $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]),
272 273
            'Variable string declaration is not correct'
        );
274
        self::assertEquals(
275
            'VARCHAR(255)',
Sergei Morozov's avatar
Sergei Morozov committed
276
            $this->platform->getVarcharTypeDeclarationSQL([]),
277 278 279 280
            'Long string declaration is not correct'
        );
    }

281
    public function getGenerateUniqueIndexSql() : string
282 283 284 285
    {
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
    }

286
    public function testGeneratesSequenceSqlCommands() : void
287
    {
Sergei Morozov's avatar
Sergei Morozov committed
288
        $sequence = new Sequence('myseq', 20, 1);
289
        self::assertEquals(
290
            'CREATE SEQUENCE myseq INCREMENT BY 20 MINVALUE 1 START 1',
Sergei Morozov's avatar
Sergei Morozov committed
291
            $this->platform->getCreateSequenceSQL($sequence)
292
        );
293
        self::assertEquals(
294
            'DROP SEQUENCE myseq CASCADE',
Sergei Morozov's avatar
Sergei Morozov committed
295
            $this->platform->getDropSequenceSQL('myseq')
296
        );
297
        self::assertEquals(
298
            "SELECT NEXTVAL('myseq')",
Sergei Morozov's avatar
Sergei Morozov committed
299
            $this->platform->getSequenceNextValSQL('myseq')
300 301 302
        );
    }

303
    public function testDoesNotPreferIdentityColumns() : void
304
    {
Sergei Morozov's avatar
Sergei Morozov committed
305
        self::assertFalse($this->platform->prefersIdentityColumns());
306 307
    }

308
    public function testPrefersSequences() : void
309
    {
Sergei Morozov's avatar
Sergei Morozov committed
310
        self::assertTrue($this->platform->prefersSequences());
311 312
    }

313
    public function testSupportsIdentityColumns() : void
314
    {
Sergei Morozov's avatar
Sergei Morozov committed
315
        self::assertTrue($this->platform->supportsIdentityColumns());
316 317
    }

318
    public function testSupportsSavePoints() : void
319
    {
Sergei Morozov's avatar
Sergei Morozov committed
320
        self::assertTrue($this->platform->supportsSavepoints());
321 322
    }

323
    public function testSupportsSequences() : void
324
    {
Sergei Morozov's avatar
Sergei Morozov committed
325
        self::assertTrue($this->platform->supportsSequences());
326 327
    }

328
    protected function supportsCommentOnStatement() : bool
329 330 331 332
    {
        return true;
    }

333
    public function testModifyLimitQuery() : void
334
    {
Sergei Morozov's avatar
Sergei Morozov committed
335
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
336
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
337 338
    }

339
    public function testModifyLimitQueryWithEmptyOffset() : void
340
    {
Sergei Morozov's avatar
Sergei Morozov committed
341
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
342
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
343 344
    }

345 346 347 348
    /**
     * {@inheritDoc}
     */
    public function getCreateTableColumnCommentsSQL() : array
349
    {
Sergei Morozov's avatar
Sergei Morozov committed
350 351
        return [
            'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))',
352
            "COMMENT ON COLUMN test.id IS 'This is a comment'",
Sergei Morozov's avatar
Sergei Morozov committed
353
        ];
354 355
    }

356 357 358 359
    /**
     * {@inheritDoc}
     */
    public function getAlterTableColumnCommentsSQL() : array
360
    {
Sergei Morozov's avatar
Sergei Morozov committed
361 362
        return [
            'ALTER TABLE mytable ADD quota INT NOT NULL',
363
            "COMMENT ON COLUMN mytable.quota IS 'A comment'",
Sergei Morozov's avatar
Sergei Morozov committed
364
            'COMMENT ON COLUMN mytable.foo IS NULL',
365
            "COMMENT ON COLUMN mytable.baz IS 'B comment'",
Sergei Morozov's avatar
Sergei Morozov committed
366
        ];
367 368
    }

369 370 371 372
    /**
     * {@inheritDoc}
     */
    public function getCreateTableColumnTypeCommentsSQL() : array
373
    {
Sergei Morozov's avatar
Sergei Morozov committed
374 375 376 377
        return [
            'CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))',
            "COMMENT ON COLUMN test.data IS '(DC2Type:array)'",
        ];
378 379
    }

380 381 382 383
    /**
     * {@inheritDoc}
     */
    protected function getQuotedColumnInPrimaryKeySQL() : array
384
    {
Sergei Morozov's avatar
Sergei Morozov committed
385
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
386 387
    }

388 389 390 391
    /**
     * {@inheritDoc}
     */
    protected function getQuotedColumnInIndexSQL() : array
392
    {
Sergei Morozov's avatar
Sergei Morozov committed
393
        return [
394 395
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
Sergei Morozov's avatar
Sergei Morozov committed
396
        ];
397 398
    }

399 400 401 402
    /**
     * {@inheritDoc}
     */
    protected function getQuotedNameInIndexSQL() : array
Markus Fasselt's avatar
Markus Fasselt committed
403
    {
Sergei Morozov's avatar
Sergei Morozov committed
404
        return [
Markus Fasselt's avatar
Markus Fasselt committed
405 406
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
            'CREATE INDEX "key" ON test (column1)',
Sergei Morozov's avatar
Sergei Morozov committed
407
        ];
Markus Fasselt's avatar
Markus Fasselt committed
408 409
    }

410 411 412 413
    /**
     * {@inheritDoc}
     */
    protected function getQuotedColumnInForeignKeySQL() : array
414
    {
Sergei Morozov's avatar
Sergei Morozov committed
415
        return [
416 417 418 419
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
            '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',
            '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',
Sergei Morozov's avatar
Sergei Morozov committed
420
        ];
421 422 423
    }

    /**
424
     * @param string|bool $databaseValue
Sergei Morozov's avatar
Sergei Morozov committed
425 426 427
     *
     * @group DBAL-457
     * @dataProvider pgBooleanProvider
428
     */
429 430
    public function testConvertBooleanAsLiteralStrings(
        $databaseValue,
431 432 433 434
        string $preparedStatementValue,
        ?int $integerValue,
        ?bool $booleanValue
    ) : void {
435 436
        $platform = $this->createPlatform();

437
        self::assertEquals($preparedStatementValue, $platform->convertBooleans($databaseValue));
438 439 440 441 442
    }

    /**
     * @group DBAL-457
     */
443
    public function testConvertBooleanAsLiteralIntegers() : void
444 445 446 447
    {
        $platform = $this->createPlatform();
        $platform->setUseBooleanTrueFalseStrings(false);

448 449
        self::assertEquals(1, $platform->convertBooleans(true));
        self::assertEquals(1, $platform->convertBooleans('1'));
450

451 452
        self::assertEquals(0, $platform->convertBooleans(false));
        self::assertEquals(0, $platform->convertBooleans('0'));
453 454 455
    }

    /**
456
     * @param string|bool $databaseValue
Sergei Morozov's avatar
Sergei Morozov committed
457 458 459
     *
     * @group DBAL-630
     * @dataProvider pgBooleanProvider
460
     */
461 462
    public function testConvertBooleanAsDatabaseValueStrings(
        $databaseValue,
463 464 465 466
        string $preparedStatementValue,
        ?int $integerValue,
        ?bool $booleanValue
    ) : void {
467 468
        $platform = $this->createPlatform();

469
        self::assertSame($integerValue, $platform->convertBooleansToDatabaseValue($booleanValue));
470 471 472 473 474
    }

    /**
     * @group DBAL-630
     */
475
    public function testConvertBooleanAsDatabaseValueIntegers() : void
476 477 478 479
    {
        $platform = $this->createPlatform();
        $platform->setUseBooleanTrueFalseStrings(false);

480 481
        self::assertSame(1, $platform->convertBooleansToDatabaseValue(true));
        self::assertSame(0, $platform->convertBooleansToDatabaseValue(false));
482
    }
483 484

    /**
485
     * @param string|bool $databaseValue
Sergei Morozov's avatar
Sergei Morozov committed
486 487
     *
     * @dataProvider pgBooleanProvider
488
     */
489
    public function testConvertFromBoolean($databaseValue, string $prepareStatementValue, ?int $integerValue, ?bool $booleanValue) : void
490 491
    {
        $platform = $this->createPlatform();
492

493
        self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue));
494
    }
495

496
    public function testThrowsExceptionWithInvalidBooleanLiteral() : void
497
    {
498 499 500 501 502 503
        $platform = $this->createPlatform();

        $this->expectException(UnexpectedValueException::class);
        $this->expectExceptionMessage("Unrecognized boolean literal 'my-bool'");

        $platform->convertBooleansToDatabaseValue('my-bool');
504 505
    }

506
    public function testGetCreateSchemaSQL() : void
507 508
    {
        $schemaName = 'schema';
Sergei Morozov's avatar
Sergei Morozov committed
509
        $sql        = $this->platform->getCreateSchemaSQL($schemaName);
510
        self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql);
511 512
    }

513
    public function testAlterDecimalPrecisionScale() : void
514 515 516
    {
        $table = new Table('mytable');
        $table->addColumn('dfoo1', 'decimal');
Sergei Morozov's avatar
Sergei Morozov committed
517 518 519
        $table->addColumn('dfoo2', 'decimal', ['precision' => 10, 'scale' => 6]);
        $table->addColumn('dfoo3', 'decimal', ['precision' => 10, 'scale' => 6]);
        $table->addColumn('dfoo4', 'decimal', ['precision' => 10, 'scale' => 6]);
520

Sergei Morozov's avatar
Sergei Morozov committed
521
        $tableDiff            = new TableDiff('mytable');
522 523
        $tableDiff->fromTable = $table;

Sergei Morozov's avatar
Sergei Morozov committed
524 525 526 527 528 529
        $tableDiff->changedColumns['dloo1'] = new ColumnDiff(
            'dloo1',
            new Column(
                'dloo1',
                Type::getType('decimal'),
                ['precision' => 16, 'scale' => 6]
530
            ),
Sergei Morozov's avatar
Sergei Morozov committed
531 532 533 534 535 536 537 538
            ['precision']
        );
        $tableDiff->changedColumns['dloo2'] = new ColumnDiff(
            'dloo2',
            new Column(
                'dloo2',
                Type::getType('decimal'),
                ['precision' => 10, 'scale' => 4]
539
            ),
Sergei Morozov's avatar
Sergei Morozov committed
540 541 542 543 544 545 546 547
            ['scale']
        );
        $tableDiff->changedColumns['dloo3'] = new ColumnDiff(
            'dloo3',
            new Column(
                'dloo3',
                Type::getType('decimal'),
                ['precision' => 10, 'scale' => 6]
548
            ),
Sergei Morozov's avatar
Sergei Morozov committed
549 550 551 552 553 554 555 556
            []
        );
        $tableDiff->changedColumns['dloo4'] = new ColumnDiff(
            'dloo4',
            new Column(
                'dloo4',
                Type::getType('decimal'),
                ['precision' => 16, 'scale' => 8]
557
            ),
Sergei Morozov's avatar
Sergei Morozov committed
558
            ['precision', 'scale']
559 560
        );

Sergei Morozov's avatar
Sergei Morozov committed
561
        $sql = $this->platform->getAlterTableSQL($tableDiff);
562

Sergei Morozov's avatar
Sergei Morozov committed
563
        $expectedSql = [
564 565 566
            'ALTER TABLE mytable ALTER dloo1 TYPE NUMERIC(16, 6)',
            'ALTER TABLE mytable ALTER dloo2 TYPE NUMERIC(10, 4)',
            'ALTER TABLE mytable ALTER dloo4 TYPE NUMERIC(16, 8)',
Sergei Morozov's avatar
Sergei Morozov committed
567
        ];
568

569
        self::assertEquals($expectedSql, $sql);
570 571 572 573 574
    }

    /**
     * @group DBAL-365
     */
575
    public function testDroppingConstraintsBeforeColumns() : void
576 577 578
    {
        $newTable = new Table('mytable');
        $newTable->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
579
        $newTable->setPrimaryKey(['id']);
580 581 582

        $oldTable = clone $newTable;
        $oldTable->addColumn('parent_id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
583
        $oldTable->addUnnamedForeignKeyConstraint('mytable', ['parent_id'], ['id']);
584

Sergei Morozov's avatar
Sergei Morozov committed
585 586
        $comparator = new Comparator();
        $tableDiff  = $comparator->diffTable($oldTable, $newTable);
587

Sergei Morozov's avatar
Sergei Morozov committed
588
        $sql = $this->platform->getAlterTableSQL($tableDiff);
589

Sergei Morozov's avatar
Sergei Morozov committed
590
        $expectedSql = [
591 592 593
            'ALTER TABLE mytable DROP CONSTRAINT FK_6B2BD609727ACA70',
            'DROP INDEX IDX_6B2BD609727ACA70',
            'ALTER TABLE mytable DROP parent_id',
Sergei Morozov's avatar
Sergei Morozov committed
594
        ];
595

596
        self::assertEquals($expectedSql, $sql);
597 598 599 600 601
    }

    /**
     * @group DBAL-563
     */
602
    public function testUsesSequenceEmulatedIdentityColumns() : void
603
    {
Sergei Morozov's avatar
Sergei Morozov committed
604
        self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns());
605 606 607 608 609
    }

    /**
     * @group DBAL-563
     */
610
    public function testReturnsIdentitySequenceName() : void
611
    {
Sergei Morozov's avatar
Sergei Morozov committed
612
        self::assertSame('mytable_mycolumn_seq', $this->platform->getIdentitySequenceName('mytable', 'mycolumn'));
613 614 615 616 617 618
    }

    /**
     * @dataProvider dataCreateSequenceWithCache
     * @group DBAL-139
     */
619
    public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void
620
    {
Sergei Morozov's avatar
Sergei Morozov committed
621
        $sequence = new Sequence('foo', 1, 1, $cacheSize);
622
        self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence));
623 624
    }

625 626 627 628
    /**
     * @return mixed[][]
     */
    public static function dataCreateSequenceWithCache() : iterable
629
    {
Sergei Morozov's avatar
Sergei Morozov committed
630 631 632
        return [
            [3, 'CACHE 3'],
        ];
633 634
    }

635
    protected function getBinaryDefaultLength() : int
636 637 638 639
    {
        return 0;
    }

640
    protected function getBinaryMaxLength() : int
641 642 643 644
    {
        return 0;
    }

645
    public function testReturnsBinaryTypeDeclarationSQL() : void
646
    {
Sergei Morozov's avatar
Sergei Morozov committed
647 648 649
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL([]));
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999]));
650

Sergei Morozov's avatar
Sergei Morozov committed
651 652 653
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999]));
654 655
    }

656
    public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void
657 658 659
    {
        $table1 = new Table('mytable');
        $table1->addColumn('column_varbinary', 'binary');
Sergei Morozov's avatar
Sergei Morozov committed
660
        $table1->addColumn('column_binary', 'binary', ['fixed' => true]);
661 662 663
        $table1->addColumn('column_blob', 'blob');

        $table2 = new Table('mytable');
Sergei Morozov's avatar
Sergei Morozov committed
664
        $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]);
665 666 667 668 669 670 671 672
        $table2->addColumn('column_binary', 'binary');
        $table2->addColumn('column_blob', 'binary');

        $comparator = new Comparator();

        // VARBINARY -> BINARY
        // BINARY    -> VARBINARY
        // BLOB      -> VARBINARY
Sergei Morozov's avatar
Sergei Morozov committed
673
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
674 675

        $table2 = new Table('mytable');
Sergei Morozov's avatar
Sergei Morozov committed
676
        $table2->addColumn('column_varbinary', 'binary', ['length' => 42]);
677
        $table2->addColumn('column_binary', 'blob');
Sergei Morozov's avatar
Sergei Morozov committed
678
        $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]);
679 680 681 682

        // VARBINARY -> VARBINARY with changed length
        // BINARY    -> BLOB
        // BLOB      -> BINARY
Sergei Morozov's avatar
Sergei Morozov committed
683
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
684 685 686

        $table2 = new Table('mytable');
        $table2->addColumn('column_varbinary', 'blob');
Sergei Morozov's avatar
Sergei Morozov committed
687
        $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]);
688 689 690 691 692
        $table2->addColumn('column_blob', 'blob');

        // VARBINARY -> BLOB
        // BINARY    -> BINARY with changed length
        // BLOB      -> BLOB
Sergei Morozov's avatar
Sergei Morozov committed
693
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
694 695 696
    }

    /**
697 698
     * {@inheritDoc}
     *
699 700
     * @group DBAL-234
     */
701
    protected function getAlterTableRenameIndexSQL() : array
702
    {
Sergei Morozov's avatar
Sergei Morozov committed
703
        return ['ALTER INDEX idx_foo RENAME TO idx_bar'];
704 705 706
    }

    /**
707 708
     * {@inheritDoc}
     *
709 710
     * @group DBAL-234
     */
711
    protected function getQuotedAlterTableRenameIndexSQL() : array
712
    {
Sergei Morozov's avatar
Sergei Morozov committed
713
        return [
714 715
            'ALTER INDEX "create" RENAME TO "select"',
            'ALTER INDEX "foo" RENAME TO "bar"',
Sergei Morozov's avatar
Sergei Morozov committed
716
        ];
717
    }
718

719 720
    /**
     * PostgreSQL boolean strings provider
Sergei Morozov's avatar
Sergei Morozov committed
721
     *
722
     * @return mixed[][]
723
     */
724
    public static function pgBooleanProvider() : iterable
725
    {
Sergei Morozov's avatar
Sergei Morozov committed
726
        return [
727
            // Database value, prepared statement value, boolean integer value, boolean value.
Sergei Morozov's avatar
Sergei Morozov committed
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
            [true, 'true', 1, true],
            ['t', 'true', 1, true],
            ['true', 'true', 1, true],
            ['y', 'true', 1, true],
            ['yes', 'true', 1, true],
            ['on', 'true', 1, true],
            ['1', 'true', 1, true],

            [false, 'false', 0, false],
            ['f', 'false', 0, false],
            ['false', 'false', 0, false],
            [ 'n', 'false', 0, false],
            ['no', 'false', 0, false],
            ['off', 'false', 0, false],
            ['0', 'false', 0, false],

            [null, 'NULL', null, null],
        ];
746 747
    }

748 749 750
    /**
     * {@inheritdoc}
     */
751
    protected function getQuotedAlterTableRenameColumnSQL() : array
752
    {
Sergei Morozov's avatar
Sergei Morozov committed
753
        return [
754 755 756 757 758 759 760 761 762
            'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted',
            'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"',
            'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"',
            'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword',
            'ALTER TABLE mytable RENAME COLUMN "table" TO "from"',
            'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"',
            'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted',
            'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"',
            'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"',
Sergei Morozov's avatar
Sergei Morozov committed
763
        ];
764
    }
765

766 767 768
    /**
     * {@inheritdoc}
     */
769
    protected function getQuotedAlterTableChangeColumnLengthSQL() : array
770
    {
Sergei Morozov's avatar
Sergei Morozov committed
771
        return [
772 773 774 775 776 777
            'ALTER TABLE mytable ALTER unquoted1 TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER unquoted2 TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER unquoted3 TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER "create" TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER "table" TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER "select" TYPE VARCHAR(255)',
Sergei Morozov's avatar
Sergei Morozov committed
778
        ];
779 780
    }

781
    /**
782 783
     * {@inheritDoc}
     *
784 785
     * @group DBAL-807
     */
786
    protected function getAlterTableRenameIndexInSchemaSQL() : array
787
    {
Sergei Morozov's avatar
Sergei Morozov committed
788
        return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar'];
789 790 791
    }

    /**
792 793
     * {@inheritDoc}
     *
794 795
     * @group DBAL-807
     */
796
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
797
    {
Sergei Morozov's avatar
Sergei Morozov committed
798
        return [
799 800
            'ALTER INDEX "schema"."create" RENAME TO "select"',
            'ALTER INDEX "schema"."foo" RENAME TO "bar"',
Sergei Morozov's avatar
Sergei Morozov committed
801
        ];
802
    }
803

804
    protected function getQuotesDropForeignKeySQL() : string
805 806 807 808
    {
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
    }

809
    public function testGetNullCommentOnColumnSQL() : void
810
    {
811
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
812
            'COMMENT ON COLUMN mytable.id IS NULL',
Sergei Morozov's avatar
Sergei Morozov committed
813
            $this->platform->getCommentOnColumnSQL('mytable', 'id', null)
814 815
        );
    }
816 817 818 819

    /**
     * @group DBAL-423
     */
820
    public function testReturnsGuidTypeDeclarationSQL() : void
821
    {
Sergei Morozov's avatar
Sergei Morozov committed
822
        self::assertSame('UUID', $this->platform->getGuidTypeDeclarationSQL([]));
823
    }
824 825 826 827

    /**
     * {@inheritdoc}
     */
828
    public function getAlterTableRenameColumnSQL() : array
829
    {
Sergei Morozov's avatar
Sergei Morozov committed
830
        return ['ALTER TABLE foo RENAME COLUMN bar TO baz'];
831
    }
832 833 834 835

    /**
     * {@inheritdoc}
     */
836
    protected function getQuotesTableIdentifiersInAlterTableSQL() : array
837
    {
Sergei Morozov's avatar
Sergei Morozov committed
838
        return [
839 840 841 842 843 844 845 846 847 848 849
            'ALTER TABLE "foo" DROP CONSTRAINT fk1',
            'ALTER TABLE "foo" DROP CONSTRAINT fk2',
            'ALTER TABLE "foo" ADD bloo INT NOT NULL',
            'ALTER TABLE "foo" DROP baz',
            'ALTER TABLE "foo" ALTER bar DROP NOT NULL',
            'ALTER TABLE "foo" RENAME COLUMN id TO war',
            'ALTER TABLE "foo" RENAME TO "table"',
            'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE ' .
            'INITIALLY IMMEDIATE',
            'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE ' .
            'INITIALLY IMMEDIATE',
Sergei Morozov's avatar
Sergei Morozov committed
850
        ];
851
    }
852 853 854 855

    /**
     * {@inheritdoc}
     */
856
    protected function getCommentOnColumnSQL() : array
857
    {
Sergei Morozov's avatar
Sergei Morozov committed
858
        return [
859 860 861
            'COMMENT ON COLUMN foo.bar IS \'comment\'',
            'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'',
            'COMMENT ON COLUMN "select"."from" IS \'comment\'',
Sergei Morozov's avatar
Sergei Morozov committed
862
        ];
863 864 865 866 867
    }

    /**
     * @group DBAL-1004
     */
868
    public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void
869
    {
Sergei Morozov's avatar
Sergei Morozov committed
870 871
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]);
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]);
872 873 874 875 876

        $comparator = new Comparator();

        $tableDiff = $comparator->diffTable($table1, $table2);

Sergei Morozov's avatar
Sergei Morozov committed
877
        self::assertInstanceOf(TableDiff::class, $tableDiff);
878
        self::assertSame(
Sergei Morozov's avatar
Sergei Morozov committed
879
            ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''],
Sergei Morozov's avatar
Sergei Morozov committed
880
            $this->platform->getAlterTableSQL($tableDiff)
881 882
        );
    }
883

884 885 886
    /**
     * @group 3158
     */
887
    public function testAltersTableColumnCommentIfRequiredByType() : void
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
    {
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime'))]);
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime_immutable'))]);

        $comparator = new Comparator();

        $tableDiff = $comparator->diffTable($table1, $table2);

        $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
        $this->assertSame(
            [
                'ALTER TABLE "foo" ALTER "bar" TYPE TIMESTAMP(0) WITHOUT TIME ZONE',
                'ALTER TABLE "foo" ALTER "bar" DROP DEFAULT',
                'COMMENT ON COLUMN "foo"."bar" IS \'(DC2Type:datetime_immutable)\'',
            ],
            $this->platform->getAlterTableSQL($tableDiff)
        );
    }

907
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
908 909 910 911
    {
        return 'CONSTRAINT "select" UNIQUE (foo)';
    }

912
    protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
913 914 915
    {
        return 'INDEX "select" (foo)';
    }
916

917
    protected function getQuotesReservedKeywordInTruncateTableSQL() : string
918 919 920 921
    {
        return 'TRUNCATE "select"';
    }

922
    /**
923
     * {@inheritdoc}
924
     */
925
    protected function getAlterStringToFixedStringSQL() : array
926
    {
Sergei Morozov's avatar
Sergei Morozov committed
927
        return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)'];
928
    }
929 930 931 932

    /**
     * {@inheritdoc}
     */
933
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array
934
    {
Sergei Morozov's avatar
Sergei Morozov committed
935
        return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed'];
936
    }
Steve Müller's avatar
Steve Müller committed
937 938 939 940

    /**
     * @group DBAL-1142
     */
941
    public function testInitializesTsvectorTypeMapping() : void
Steve Müller's avatar
Steve Müller committed
942
    {
Sergei Morozov's avatar
Sergei Morozov committed
943 944
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector'));
        self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector'));
Steve Müller's avatar
Steve Müller committed
945
    }
946 947 948 949

    /**
     * @group DBAL-1220
     */
950
    public function testReturnsDisallowDatabaseConnectionsSQL() : void
951
    {
952
        self::assertSame(
953
            "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'",
Sergei Morozov's avatar
Sergei Morozov committed
954
            $this->platform->getDisallowDatabaseConnectionsSQL('foo')
955 956 957 958 959 960
        );
    }

    /**
     * @group DBAL-1220
     */
961
    public function testReturnsCloseActiveDatabaseConnectionsSQL() : void
962
    {
963
        self::assertSame(
964
            "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'",
Sergei Morozov's avatar
Sergei Morozov committed
965
            $this->platform->getCloseActiveDatabaseConnectionsSQL('foo')
966 967
        );
    }
968 969 970 971

    /**
     * @group DBAL-2436
     */
972
    public function testQuotesTableNameInListTableForeignKeysSQL() : void
973
    {
974 975 976 977
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\")
        );
978 979 980 981 982
    }

    /**
     * @group DBAL-2436
     */
983
    public function testQuotesSchemaNameInListTableForeignKeysSQL() : void
984
    {
985
        self::assertStringContainsStringIgnoringCase(
986
            "'Foo''Bar\\'",
987
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table")
988 989 990 991 992 993
        );
    }

    /**
     * @group DBAL-2436
     */
994
    public function testQuotesTableNameInListTableConstraintsSQL() : void
995
    {
996 997 998 999
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableConstraintsSQL("Foo'Bar\\")
        );
1000 1001 1002 1003 1004
    }

    /**
     * @group DBAL-2436
     */
1005
    public function testQuotesTableNameInListTableIndexesSQL() : void
1006
    {
1007 1008 1009 1010
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableIndexesSQL("Foo'Bar\\")
        );
1011 1012 1013 1014 1015
    }

    /**
     * @group DBAL-2436
     */
1016
    public function testQuotesSchemaNameInListTableIndexesSQL() : void
1017
    {
1018
        self::assertStringContainsStringIgnoringCase(
1019
            "'Foo''Bar\\'",
1020
            $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table")
1021 1022 1023 1024 1025 1026
        );
    }

    /**
     * @group DBAL-2436
     */
1027
    public function testQuotesTableNameInListTableColumnsSQL() : void
1028
    {
1029 1030 1031 1032
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableColumnsSQL("Foo'Bar\\")
        );
1033 1034 1035 1036 1037
    }

    /**
     * @group DBAL-2436
     */
1038
    public function testQuotesSchemaNameInListTableColumnsSQL() : void
1039
    {
1040
        self::assertStringContainsStringIgnoringCase(
1041
            "'Foo''Bar\\'",
1042
            $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table")
1043 1044 1045 1046 1047 1048
        );
    }

    /**
     * @group DBAL-2436
     */
1049
    public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void
1050
    {
1051
        self::assertStringContainsStringIgnoringCase(
1052
            "'Foo''Bar\\'",
1053
            $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\")
1054 1055
        );
    }
1056
}