Failed Conditions
Pull Request — develop (#3348)
by Sergei
72:11 queued 07:06
created

testGetNullCommentOnColumnSQL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

433
        /** @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...
434
        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

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

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

447
        $platform->/** @scrutinizer ignore-call */ 
448
                   setUseBooleanTrueFalseStrings(false);
Loading history...
448
449
        self::assertEquals(1, $platform->convertBooleans(true));
450
        self::assertEquals(1, $platform->convertBooleans('1'));
451
452
        self::assertEquals(0, $platform->convertBooleans(false));
453
        self::assertEquals(0, $platform->convertBooleans('0'));
454
    }
455
456
    /**
457
     * @group DBAL-630
458
     * @dataProvider pgBooleanProvider
459
     */
460
    public function testConvertBooleanAsDatabaseValueStrings(
461
        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

461
        /** @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...
462
        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

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

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

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

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

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

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

486
    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...
487
    {
488
        $platform = $this->createPlatform();
489
490
        self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue));
491
    }
492
493
    public function testThrowsExceptionWithInvalidBooleanLiteral() : void
494
    {
495
        $platform = $this->createPlatform();
496
497
        $this->expectException(UnexpectedValueException::class);
498
        $this->expectExceptionMessage("Unrecognized boolean literal 'my-bool'");
499
500
        $platform->convertBooleansToDatabaseValue('my-bool');
501
    }
502
503
    public function testGetCreateSchemaSQL() : void
504
    {
505
        $schemaName = 'schema';
506
        $sql        = $this->platform->getCreateSchemaSQL($schemaName);
507
        self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql);
508
    }
509
510
    public function testAlterDecimalPrecisionScale() : void
511
    {
512
        $table = new Table('mytable');
513
        $table->addColumn('dfoo1', 'decimal');
514
        $table->addColumn('dfoo2', 'decimal', ['precision' => 10, 'scale' => 6]);
515
        $table->addColumn('dfoo3', 'decimal', ['precision' => 10, 'scale' => 6]);
516
        $table->addColumn('dfoo4', 'decimal', ['precision' => 10, 'scale' => 6]);
517
518
        $tableDiff            = new TableDiff('mytable');
519
        $tableDiff->fromTable = $table;
520
521
        $tableDiff->changedColumns['dloo1'] = new ColumnDiff(
522
            'dloo1',
523
            new Column(
524
                'dloo1',
525
                Type::getType('decimal'),
526
                ['precision' => 16, 'scale' => 6]
527
            ),
528
            ['precision']
529
        );
530
        $tableDiff->changedColumns['dloo2'] = new ColumnDiff(
531
            'dloo2',
532
            new Column(
533
                'dloo2',
534
                Type::getType('decimal'),
535
                ['precision' => 10, 'scale' => 4]
536
            ),
537
            ['scale']
538
        );
539
        $tableDiff->changedColumns['dloo3'] = new ColumnDiff(
540
            'dloo3',
541
            new Column(
542
                'dloo3',
543
                Type::getType('decimal'),
544
                ['precision' => 10, 'scale' => 6]
545
            ),
546
            []
547
        );
548
        $tableDiff->changedColumns['dloo4'] = new ColumnDiff(
549
            'dloo4',
550
            new Column(
551
                'dloo4',
552
                Type::getType('decimal'),
553
                ['precision' => 16, 'scale' => 8]
554
            ),
555
            ['precision', 'scale']
556
        );
557
558
        $sql = $this->platform->getAlterTableSQL($tableDiff);
559
560
        $expectedSql = [
561
            'ALTER TABLE mytable ALTER dloo1 TYPE NUMERIC(16, 6)',
562
            'ALTER TABLE mytable ALTER dloo2 TYPE NUMERIC(10, 4)',
563
            'ALTER TABLE mytable ALTER dloo4 TYPE NUMERIC(16, 8)',
564
        ];
565
566
        self::assertEquals($expectedSql, $sql);
567
    }
568
569
    /**
570
     * @group DBAL-365
571
     */
572
    public function testDroppingConstraintsBeforeColumns() : void
573
    {
574
        $newTable = new Table('mytable');
575
        $newTable->addColumn('id', 'integer');
576
        $newTable->setPrimaryKey(['id']);
577
578
        $oldTable = clone $newTable;
579
        $oldTable->addColumn('parent_id', 'integer');
580
        $oldTable->addUnnamedForeignKeyConstraint('mytable', ['parent_id'], ['id']);
1 ignored issue
show
Deprecated Code introduced by
The function Doctrine\DBAL\Schema\Tab...dForeignKeyConstraint() has been deprecated: Use {@link addForeignKeyConstraint} ( Ignorable by Annotation )

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

580
        /** @scrutinizer ignore-deprecated */ $oldTable->addUnnamedForeignKeyConstraint('mytable', ['parent_id'], ['id']);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
581
582
        $comparator = new Comparator();
583
        $tableDiff  = $comparator->diffTable($oldTable, $newTable);
584
585
        $sql = $this->platform->getAlterTableSQL($tableDiff);
0 ignored issues
show
Bug introduced by
It seems like $tableDiff can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

585
        $sql = $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $tableDiff);
Loading history...
586
587
        $expectedSql = [
588
            'ALTER TABLE mytable DROP CONSTRAINT FK_6B2BD609727ACA70',
589
            'DROP INDEX IDX_6B2BD609727ACA70',
590
            'ALTER TABLE mytable DROP parent_id',
591
        ];
592
593
        self::assertEquals($expectedSql, $sql);
594
    }
595
596
    /**
597
     * @group DBAL-563
598
     */
599
    public function testUsesSequenceEmulatedIdentityColumns() : void
600
    {
601
        self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns());
602
    }
603
604
    /**
605
     * @group DBAL-563
606
     */
607
    public function testReturnsIdentitySequenceName() : void
608
    {
609
        self::assertSame('mytable_mycolumn_seq', $this->platform->getIdentitySequenceName('mytable', 'mycolumn'));
610
    }
611
612
    /**
613
     * @dataProvider dataCreateSequenceWithCache
614
     * @group DBAL-139
615
     */
616
    public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void
617
    {
618
        $sequence = new Sequence('foo', 1, 1, $cacheSize);
619
        self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence));
620
    }
621
622
    /**
623
     * @return mixed[][]
624
     */
625
    public static function dataCreateSequenceWithCache() : iterable
626
    {
627
        return [
628
            [3, 'CACHE 3'],
629
        ];
630
    }
631
632
    protected function getBinaryDefaultLength() : int
633
    {
634
        return 0;
635
    }
636
637
    protected function getBinaryMaxLength() : int
638
    {
639
        return 0;
640
    }
641
642
    public function testReturnsBinaryTypeDeclarationSQL() : void
643
    {
644
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL([]));
645
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
646
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999]));
647
648
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
649
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
650
        self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999]));
651
    }
652
653
    public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void
654
    {
655
        $table1 = new Table('mytable');
656
        $table1->addColumn('column_varbinary', 'binary');
657
        $table1->addColumn('column_binary', 'binary', ['fixed' => true]);
658
        $table1->addColumn('column_blob', 'blob');
659
660
        $table2 = new Table('mytable');
661
        $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]);
662
        $table2->addColumn('column_binary', 'binary');
663
        $table2->addColumn('column_blob', 'binary');
664
665
        $comparator = new Comparator();
666
667
        // VARBINARY -> BINARY
668
        // BINARY    -> VARBINARY
669
        // BLOB      -> VARBINARY
670
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
0 ignored issues
show
Bug introduced by
It seems like $comparator->diffTable($table1, $table2) can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

670
        self::assertEmpty($this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $comparator->diffTable($table1, $table2)));
Loading history...
671
672
        $table2 = new Table('mytable');
673
        $table2->addColumn('column_varbinary', 'binary', ['length' => 42]);
674
        $table2->addColumn('column_binary', 'blob');
675
        $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]);
676
677
        // VARBINARY -> VARBINARY with changed length
678
        // BINARY    -> BLOB
679
        // BLOB      -> BINARY
680
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
681
682
        $table2 = new Table('mytable');
683
        $table2->addColumn('column_varbinary', 'blob');
684
        $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]);
685
        $table2->addColumn('column_blob', 'blob');
686
687
        // VARBINARY -> BLOB
688
        // BINARY    -> BINARY with changed length
689
        // BLOB      -> BLOB
690
        self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2)));
691
    }
692
693
    /**
694
     * {@inheritDoc}
695
     *
696
     * @group DBAL-234
697
     */
698
    protected function getAlterTableRenameIndexSQL() : array
699
    {
700
        return ['ALTER INDEX idx_foo RENAME TO idx_bar'];
701
    }
702
703
    /**
704
     * {@inheritDoc}
705
     *
706
     * @group DBAL-234
707
     */
708
    protected function getQuotedAlterTableRenameIndexSQL() : array
709
    {
710
        return [
711
            'ALTER INDEX "create" RENAME TO "select"',
712
            'ALTER INDEX "foo" RENAME TO "bar"',
713
        ];
714
    }
715
716
    /**
717
     * PostgreSQL boolean strings provider
718
     *
719
     * @return mixed[][]
720
     */
721
    public static function pgBooleanProvider() : iterable
722
    {
723
        return [
724
            // Database value, prepared statement value, boolean integer value, boolean value.
725
            ['t', 'true', 1, true],
726
            ['true', 'true', 1, true],
727
            ['y', 'true', 1, true],
728
            ['yes', 'true', 1, true],
729
            ['on', 'true', 1, true],
730
            ['1', 'true', 1, true],
731
732
            ['f', 'false', 0, false],
733
            ['false', 'false', 0, false],
734
            [ 'n', 'false', 0, false],
735
            ['no', 'false', 0, false],
736
            ['off', 'false', 0, false],
737
            ['0', 'false', 0, false],
738
        ];
739
    }
740
741
    /**
742
     * {@inheritdoc}
743
     */
744
    protected function getQuotedAlterTableRenameColumnSQL() : array
745
    {
746
        return [
747
            'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted',
748
            'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"',
749
            'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"',
750
            'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword',
751
            'ALTER TABLE mytable RENAME COLUMN "table" TO "from"',
752
            'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"',
753
            'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted',
754
            'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"',
755
            'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"',
756
        ];
757
    }
758
759
    /**
760
     * {@inheritdoc}
761
     */
762
    protected function getQuotedAlterTableChangeColumnLengthSQL() : array
763
    {
764
        return [
765
            'ALTER TABLE mytable ALTER unquoted1 TYPE VARCHAR(255)',
766
            'ALTER TABLE mytable ALTER unquoted2 TYPE VARCHAR(255)',
767
            'ALTER TABLE mytable ALTER unquoted3 TYPE VARCHAR(255)',
768
            'ALTER TABLE mytable ALTER "create" TYPE VARCHAR(255)',
769
            'ALTER TABLE mytable ALTER "table" TYPE VARCHAR(255)',
770
            'ALTER TABLE mytable ALTER "select" TYPE VARCHAR(255)',
771
        ];
772
    }
773
774
    /**
775
     * {@inheritDoc}
776
     *
777
     * @group DBAL-807
778
     */
779
    protected function getAlterTableRenameIndexInSchemaSQL() : array
780
    {
781
        return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar'];
782
    }
783
784
    /**
785
     * {@inheritDoc}
786
     *
787
     * @group DBAL-807
788
     */
789
    protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array
790
    {
791
        return [
792
            'ALTER INDEX "schema"."create" RENAME TO "select"',
793
            'ALTER INDEX "schema"."foo" RENAME TO "bar"',
794
        ];
795
    }
796
797
    protected function getQuotesDropForeignKeySQL() : string
798
    {
799
        return 'ALTER TABLE "table" DROP CONSTRAINT "select"';
800
    }
801
802
    /**
803
     * @group DBAL-423
804
     */
805
    public function testReturnsGuidTypeDeclarationSQL() : void
806
    {
807
        self::assertSame('UUID', $this->platform->getGuidTypeDeclarationSQL([]));
808
    }
809
810
    /**
811
     * {@inheritdoc}
812
     */
813
    public function getAlterTableRenameColumnSQL() : array
814
    {
815
        return ['ALTER TABLE foo RENAME COLUMN bar TO baz'];
816
    }
817
818
    /**
819
     * {@inheritdoc}
820
     */
821
    protected function getQuotesTableIdentifiersInAlterTableSQL() : array
822
    {
823
        return [
824
            'ALTER TABLE "foo" DROP CONSTRAINT fk1',
825
            'ALTER TABLE "foo" DROP CONSTRAINT fk2',
826
            'ALTER TABLE "foo" ADD bloo INT NOT NULL',
827
            'ALTER TABLE "foo" DROP baz',
828
            'ALTER TABLE "foo" ALTER bar DROP NOT NULL',
829
            'ALTER TABLE "foo" RENAME COLUMN id TO war',
830
            'ALTER TABLE "foo" RENAME TO "table"',
831
            'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE ' .
832
            'INITIALLY IMMEDIATE',
833
            'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE ' .
834
            'INITIALLY IMMEDIATE',
835
        ];
836
    }
837
838
    /**
839
     * {@inheritdoc}
840
     */
841
    protected function getCommentOnColumnSQL() : array
842
    {
843
        return [
844
            'COMMENT ON COLUMN foo.bar IS \'comment\'',
845
            'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'',
846
            'COMMENT ON COLUMN "select"."from" IS \'comment\'',
847
        ];
848
    }
849
850
    /**
851
     * @group DBAL-1004
852
     */
853
    public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void
854
    {
855
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]);
856
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]);
857
858
        $comparator = new Comparator();
859
860
        $tableDiff = $comparator->diffTable($table1, $table2);
861
862
        self::assertInstanceOf(TableDiff::class, $tableDiff);
863
        self::assertSame(
864
            ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''],
865
            $this->platform->getAlterTableSQL($tableDiff)
0 ignored issues
show
Bug introduced by
It seems like $tableDiff can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

865
            $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $tableDiff)
Loading history...
866
        );
867
    }
868
869
    /**
870
     * @group 3158
871
     */
872
    public function testAltersTableColumnCommentIfRequiredByType() : void
873
    {
874
        $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime'))]);
875
        $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime_immutable'))]);
876
877
        $comparator = new Comparator();
878
879
        $tableDiff = $comparator->diffTable($table1, $table2);
880
881
        $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
882
        $this->assertSame(
883
            [
884
                'ALTER TABLE "foo" ALTER "bar" TYPE TIMESTAMP(0) WITHOUT TIME ZONE',
885
                'ALTER TABLE "foo" ALTER "bar" DROP DEFAULT',
886
                'COMMENT ON COLUMN "foo"."bar" IS \'(DC2Type:datetime_immutable)\'',
887
            ],
888
            $this->platform->getAlterTableSQL($tableDiff)
0 ignored issues
show
Bug introduced by
It seems like $tableDiff can also be of type false; however, parameter $diff of Doctrine\DBAL\Platforms\...orm::getAlterTableSQL() does only seem to accept Doctrine\DBAL\Schema\TableDiff, maybe add an additional type check? ( Ignorable by Annotation )

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

888
            $this->platform->getAlterTableSQL(/** @scrutinizer ignore-type */ $tableDiff)
Loading history...
889
        );
890
    }
891
892
    /**
893
     * {@inheritdoc}
894
     */
895
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
896
    {
897
        return 'CONSTRAINT "select" UNIQUE (foo)';
898
    }
899
900
    /**
901
     * {@inheritdoc}
902
     */
903
    protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
904
    {
905
        return 'INDEX "select" (foo)';
906
    }
907
908
    /**
909
     * {@inheritdoc}
910
     */
911
    protected function getQuotesReservedKeywordInTruncateTableSQL() : string
912
    {
913
        return 'TRUNCATE "select"';
914
    }
915
916
    /**
917
     * {@inheritdoc}
918
     */
919
    protected function getAlterStringToFixedStringSQL() : array
920
    {
921
        return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)'];
922
    }
923
924
    /**
925
     * {@inheritdoc}
926
     */
927
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array
928
    {
929
        return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed'];
930
    }
931
932
    /**
933
     * @group DBAL-1142
934
     */
935
    public function testInitializesTsvectorTypeMapping() : void
936
    {
937
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector'));
938
        self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector'));
939
    }
940
941
    /**
942
     * @group DBAL-1220
943
     */
944
    public function testReturnsDisallowDatabaseConnectionsSQL() : void
945
    {
946
        self::assertSame(
947
            "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'",
948
            $this->platform->getDisallowDatabaseConnectionsSQL('foo')
0 ignored issues
show
Bug introduced by
The method getDisallowDatabaseConnectionsSQL() does not exist on Doctrine\DBAL\Platforms\AbstractPlatform. It seems like you code against a sub-type of Doctrine\DBAL\Platforms\AbstractPlatform such as Doctrine\DBAL\Platforms\PostgreSqlPlatform. ( Ignorable by Annotation )

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

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

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

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