AbstractPostgreSqlPlatformTestCase.php 33.7 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 329 330
    /**
     * {@inheritdoc}
     */
331
    protected function supportsCommentOnStatement() : bool
332 333 334 335
    {
        return true;
    }

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

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

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

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

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

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

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

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

413 414 415 416
    /**
     * {@inheritDoc}
     */
    protected function getQuotedColumnInForeignKeySQL() : array
417
    {
Sergei Morozov's avatar
Sergei Morozov committed
418
        return [
419 420 421 422
            '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
423
        ];
424 425 426
    }

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

440
        self::assertEquals($preparedStatementValue, $platform->convertBooleans($databaseValue));
441 442 443 444 445
    }

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

451 452
        self::assertEquals(1, $platform->convertBooleans(true));
        self::assertEquals(1, $platform->convertBooleans('1'));
453

454 455
        self::assertEquals(0, $platform->convertBooleans(false));
        self::assertEquals(0, $platform->convertBooleans('0'));
456 457 458
    }

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

472
        self::assertSame($integerValue, $platform->convertBooleansToDatabaseValue($booleanValue));
473 474 475 476 477
    }

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

483 484
        self::assertSame(1, $platform->convertBooleansToDatabaseValue(true));
        self::assertSame(0, $platform->convertBooleansToDatabaseValue(false));
485
    }
486 487

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

496
        self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue));
497
    }
498

499
    public function testThrowsExceptionWithInvalidBooleanLiteral() : void
500
    {
501 502 503 504 505 506
        $platform = $this->createPlatform();

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

        $platform->convertBooleansToDatabaseValue('my-bool');
507 508
    }

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

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

Sergei Morozov's avatar
Sergei Morozov committed
524
        $tableDiff            = new TableDiff('mytable');
525 526
        $tableDiff->fromTable = $table;

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

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

Sergei Morozov's avatar
Sergei Morozov committed
566
        $expectedSql = [
567 568 569
            '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
570
        ];
571

572
        self::assertEquals($expectedSql, $sql);
573 574 575 576 577
    }

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

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

Sergei Morozov's avatar
Sergei Morozov committed
588 589
        $comparator = new Comparator();
        $tableDiff  = $comparator->diffTable($oldTable, $newTable);
590

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

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

599
        self::assertEquals($expectedSql, $sql);
600 601 602 603 604
    }

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

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

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

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

638
    protected function getBinaryDefaultLength() : int
639 640 641 642
    {
        return 0;
    }

643
    protected function getBinaryMaxLength() : int
644 645 646 647
    {
        return 0;
    }

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

Sergei Morozov's avatar
Sergei Morozov committed
654 655 656
        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]));
657 658
    }

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

        $table2 = new Table('mytable');
Sergei Morozov's avatar
Sergei Morozov committed
667
        $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]);
668 669 670 671 672 673 674 675
        $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
676
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
677 678

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

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

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

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

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

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

722 723
    /**
     * PostgreSQL boolean strings provider
Sergei Morozov's avatar
Sergei Morozov committed
724
     *
725
     * @return mixed[][]
726
     */
727
    public static function pgBooleanProvider() : iterable
728
    {
Sergei Morozov's avatar
Sergei Morozov committed
729
        return [
730
            // Database value, prepared statement value, boolean integer value, boolean value.
Sergei Morozov's avatar
Sergei Morozov committed
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
            [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],
        ];
749 750
    }

751 752 753
    /**
     * {@inheritdoc}
     */
754
    protected function getQuotedAlterTableRenameColumnSQL() : array
755
    {
Sergei Morozov's avatar
Sergei Morozov committed
756
        return [
757 758 759 760 761 762 763 764 765
            '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
766
        ];
767
    }
768

769 770 771
    /**
     * {@inheritdoc}
     */
772
    protected function getQuotedAlterTableChangeColumnLengthSQL() : array
773
    {
Sergei Morozov's avatar
Sergei Morozov committed
774
        return [
775 776 777 778 779 780
            '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
781
        ];
782 783
    }

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

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

807
    protected function getQuotesDropForeignKeySQL() : string
808 809 810 811
    {
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
    }

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

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

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

    /**
     * {@inheritdoc}
     */
839
    protected function getQuotesTableIdentifiersInAlterTableSQL() : array
840
    {
Sergei Morozov's avatar
Sergei Morozov committed
841
        return [
842 843 844 845 846 847 848 849 850 851 852
            '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
853
        ];
854
    }
855 856 857 858

    /**
     * {@inheritdoc}
     */
859
    protected function getCommentOnColumnSQL() : array
860
    {
Sergei Morozov's avatar
Sergei Morozov committed
861
        return [
862 863 864
            '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
865
        ];
866 867 868 869 870
    }

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

        $comparator = new Comparator();

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

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

887 888 889
    /**
     * @group 3158
     */
890
    public function testAltersTableColumnCommentIfRequiredByType() : void
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
    {
        $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)
        );
    }

910 911 912
    /**
     * {@inheritdoc}
     */
913
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
914 915 916 917 918 919 920
    {
        return 'CONSTRAINT "select" UNIQUE (foo)';
    }

    /**
     * {@inheritdoc}
     */
921
    protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
922 923 924
    {
        return 'INDEX "select" (foo)';
    }
925

926 927 928
    /**
     * {@inheritdoc}
     */
929
    protected function getQuotesReservedKeywordInTruncateTableSQL() : string
930 931 932 933
    {
        return 'TRUNCATE "select"';
    }

934
    /**
935
     * {@inheritdoc}
936
     */
937
    protected function getAlterStringToFixedStringSQL() : array
938
    {
Sergei Morozov's avatar
Sergei Morozov committed
939
        return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)'];
940
    }
941 942 943 944

    /**
     * {@inheritdoc}
     */
945
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array
946
    {
Sergei Morozov's avatar
Sergei Morozov committed
947
        return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed'];
948
    }
Steve Müller's avatar
Steve Müller committed
949 950 951 952

    /**
     * @group DBAL-1142
     */
953
    public function testInitializesTsvectorTypeMapping() : void
Steve Müller's avatar
Steve Müller committed
954
    {
Sergei Morozov's avatar
Sergei Morozov committed
955 956
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector'));
        self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector'));
Steve Müller's avatar
Steve Müller committed
957
    }
958 959 960 961

    /**
     * @group DBAL-1220
     */
962
    public function testReturnsDisallowDatabaseConnectionsSQL() : void
963
    {
964
        self::assertSame(
965
            "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'",
Sergei Morozov's avatar
Sergei Morozov committed
966
            $this->platform->getDisallowDatabaseConnectionsSQL('foo')
967 968 969 970 971 972
        );
    }

    /**
     * @group DBAL-1220
     */
973
    public function testReturnsCloseActiveDatabaseConnectionsSQL() : void
974
    {
975
        self::assertSame(
976
            "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'",
Sergei Morozov's avatar
Sergei Morozov committed
977
            $this->platform->getCloseActiveDatabaseConnectionsSQL('foo')
978 979
        );
    }
980 981 982 983

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

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

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

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

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

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

    /**
     * @group DBAL-2436
     */
1050
    public function testQuotesSchemaNameInListTableColumnsSQL() : void
1051
    {
1052
        self::assertStringContainsStringIgnoringCase(
1053
            "'Foo''Bar\\'",
1054
            $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table")
1055 1056 1057 1058 1059 1060
        );
    }

    /**
     * @group DBAL-2436
     */
1061
    public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void
1062
    {
1063
        self::assertStringContainsStringIgnoringCase(
1064
            "'Foo''Bar\\'",
1065
            $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\")
1066 1067
        );
    }
1068
}