Failed Conditions
Push — master ( 01143c...7811e4 )
by Sergei
21s queued 14s
created

AbstractPostgreSQLPlatformTestCase   F

Complexity

Total Complexity 80

Size/Duplication

Total Lines 1011
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 80
eloc 392
dl 0
loc 1011
rs 2
c 0
b 0
f 0

80 Methods

Rating   Name   Duplication   Size   Complexity  
A getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() 0 3 1
A testQuotesSchemaNameInListTableColumnsSQL() 0 5 1
A testConvertFromBoolean() 0 3 1
A getGenerateIndexSql() 0 3 1
A getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() 0 3 1
A testGeneratesTransactionCommands() 0 17 1
A getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() 0 3 1
A getQuotedColumnInIndexSQL() 0 5 1
A getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() 0 3 1
A testCreateSequenceWithCache() 0 4 1
A testGenerateTableWithAutoincrement() 0 7 1
A testGenerateTableWithAutoincrementDoesNotSetDefault() 0 10 1
A testGetDefaultValueDeclarationSQLIgnoresTheDefaultKeyWhenTheFieldIsSerial() 0 11 1
A getQuotedAlterTableRenameIndexSQL() 0 5 1
A testModifyLimitQuery() 0 4 1
A getCommentOnColumnSQL() 0 6 1
A testReturnsCloseActiveDatabaseConnectionsSQL() 0 7 1
A getCreateTableColumnCommentsSQL() 0 5 1
A getGenerateTableWithMultiColumnUniqueIndexSql() 0 5 1
A testUsesSequenceEmulatedIdentityColumns() 0 3 1
A supportsCommentOnStatement() 0 3 1
A testGeneratesSqlSnippets() 0 7 1
A testPrefersSequences() 0 3 1
A getCreateTableColumnTypeCommentsSQL() 0 5 1
A getAlterTableRenameIndexInSchemaSQL() 0 3 1
A testDoesNotPreferIdentityColumns() 0 3 1
A getAlterTableColumnCommentsSQL() 0 7 1
A testConvertBooleanAsLiteralStrings() 0 7 1
A pgBooleanProvider() 0 17 1
A testInitializesTsvectorTypeMapping() 0 4 1
A testQuotesSchemaNameInListTableForeignKeysSQL() 0 5 1
A testReturnsGuidTypeDeclarationSQL() 0 3 1
A testReturnsIdentitySequenceName() 0 3 1
A testAltersTableColumnCommentIfRequiredByType() 0 17 1
A testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() 0 50 1
A getAlterStringToFixedStringSQL() 0 3 1
A testAlterDecimalPrecisionScale() 0 57 1
A testConvertBooleanAsDatabaseValueIntegers() 0 6 1
A getQuotesDropForeignKeySQL() 0 3 1
A getQuotedAlterTableChangeColumnLengthSQL() 0 9 1
A getQuotesTableIdentifiersInAlterTableSQL() 0 14 1
A getQuotesReservedKeywordInIndexDeclarationSQL() 0 3 1
A getGenerateUniqueIndexSql() 0 3 1
A testQuotesTableNameInListTableForeignKeysSQL() 0 5 1
A getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() 0 3 1
A getGenerateAlterTableSql() 0 12 1
A testConvertBooleanAsDatabaseValueStrings() 0 7 1
A testModifyLimitQueryWithEmptyOffset() 0 4 1
A getQuotesReservedKeywordInTruncateTableSQL() 0 3 1
A testQuotesSchemaNameInListTableIndexesSQL() 0 5 1
A testSupportsSavePoints() 0 3 1
A testGetCreateSchemaSQL() 0 5 1
A testConvertBooleanAsLiteralIntegers() 0 9 1
A testQuotesTableNameInListTableConstraintsSQL() 0 5 1
A testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() 0 13 1
A testGeneratesTypeDeclarationForIntegers() 0 14 1
A getQuotedAlterTableRenameColumnSQL() 0 12 1
A serialTypes() 0 5 1
A testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() 0 7 1
A getGenerateForeignKeySql() 0 3 1
A getQuotedColumnInPrimaryKeySQL() 0 3 1
A testGeneratesForeignKeySqlForNonStandardOptions() 0 72 1
A testGeneratesDDLSnippets() 0 5 1
A getQuotedNameInIndexSQL() 0 5 1
A getQuotedAlterTableRenameIndexInSchemaSQL() 0 5 1
A testCreateTableWithAutoincrementAndNotNullAddsConstraint() 0 10 1
A getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() 0 3 1
A testDroppingConstraintsBeforeColumns() 0 24 1
A testThrowsExceptionWithInvalidBooleanLiteral() 0 6 1
A getGenerateTableSql() 0 3 1
A testGeneratesSequenceSqlCommands() 0 14 1
A dataCreateSequenceWithCache() 0 4 1
A testQuotesTableNameInListTableIndexesSQL() 0 5 1
A testSupportsSequences() 0 3 1
A testReturnsDisallowDatabaseConnectionsSQL() 0 7 1
A getQuotedColumnInForeignKeySQL() 0 7 1
A testQuotesTableNameInListTableColumnsSQL() 0 5 1
A getAlterTableRenameColumnSQL() 0 3 1
A testSupportsIdentityColumns() 0 3 1
A getAlterTableRenameIndexSQL() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractPostgreSQLPlatformTestCase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractPostgreSQLPlatformTestCase, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Platforms;
6
7
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
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 PostgreSQL94Platform */
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
    public function testGeneratesTransactionCommands() : void
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
    public function testGenerateTableWithAutoincrement() : void
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
    public function testGenerateTableWithAutoincrementDoesNotSetDefault(string $type, string $definition) : void
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
    public function testCreateTableWithAutoincrementAndNotNullAddsConstraint(string $type, string $definition) : void
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
    public function testGeneratesTypeDeclarationForIntegers() : void
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
    protected function supportsCommentOnStatement() : bool
316
    {
317
        return true;
318
    }
319
320
    public function testModifyLimitQuery() : void
321
    {
322
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0);
323
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
324
    }
325
326
    public function testModifyLimitQueryWithEmptyOffset() : void
327
    {
328
        $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10);
329
        self::assertEquals('SELECT * FROM user LIMIT 10', $sql);
330
    }
331
332
    /**
333
     * {@inheritDoc}
334
     */
335
    public function getCreateTableColumnCommentsSQL() : array
336
    {
337
        return [
338
            'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))',
339
            "COMMENT ON COLUMN test.id IS 'This is a comment'",
340
        ];
341
    }
342
343
    /**
344
     * {@inheritDoc}
345
     */
346
    public function getAlterTableColumnCommentsSQL() : array
347
    {
348
        return [
349
            'ALTER TABLE mytable ADD quota INT NOT NULL',
350
            "COMMENT ON COLUMN mytable.quota IS 'A comment'",
351
            'COMMENT ON COLUMN mytable.foo IS NULL',
352
            "COMMENT ON COLUMN mytable.baz IS 'B comment'",
353
        ];
354
    }
355
356
    /**
357
     * {@inheritDoc}
358
     */
359
    public function getCreateTableColumnTypeCommentsSQL() : array
360
    {
361
        return [
362
            'CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))',
363
            "COMMENT ON COLUMN test.data IS '(DC2Type:array)'",
364
        ];
365
    }
366
367
    /**
368
     * {@inheritDoc}
369
     */
370
    protected function getQuotedColumnInPrimaryKeySQL() : array
371
    {
372
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
373
    }
374
375
    /**
376
     * {@inheritDoc}
377
     */
378
    protected function getQuotedColumnInIndexSQL() : array
379
    {
380
        return [
381
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
382
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
383
        ];
384
    }
385
386
    /**
387
     * {@inheritDoc}
388
     */
389
    protected function getQuotedNameInIndexSQL() : array
390
    {
391
        return [
392
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
393
            'CREATE INDEX "key" ON test (column1)',
394
        ];
395
    }
396
397
    /**
398
     * {@inheritDoc}
399
     */
400
    protected function getQuotedColumnInForeignKeySQL() : array
401
    {
402
        return [
403
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
404
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE',
405
            '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',
406
            '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',
407
        ];
408
    }
409
410
    /**
411
     * @group DBAL-457
412
     * @dataProvider pgBooleanProvider
413
     */
414
    public function testConvertBooleanAsLiteralStrings(
415
        string $databaseValue,
416
        string $preparedStatementValue,
417
        int $integerValue,
0 ignored issues
show
Unused Code introduced by
The parameter $integerValue is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
444
        int $integerValue,
445
        bool $booleanValue
446
    ) : void {
447
        self::assertSame($integerValue, $this->platform->convertBooleansToDatabaseValue($booleanValue));
448
    }
449
450
    /**
451
     * @group DBAL-630
452
     */
453
    public function testConvertBooleanAsDatabaseValueIntegers() : void
454
    {
455
        $this->platform->setUseBooleanTrueFalseStrings(false);
456
457
        self::assertSame(1, $this->platform->convertBooleansToDatabaseValue(true));
458
        self::assertSame(0, $this->platform->convertBooleansToDatabaseValue(false));
459
    }
460
461
    /**
462
     * @dataProvider pgBooleanProvider
463
     */
464
    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. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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