Passed
Pull Request — master (#2893)
by Šimon
14:29 queued 16s
created

PostgreSqlPlatform   F

Complexity

Total Complexity 167

Size/Duplication

Total Lines 1200
Duplicated Lines 11.75 %

Test Coverage

Coverage 78.3%

Importance

Changes 0
Metric Value
wmc 167
dl 141
loc 1200
ccs 249
cts 318
cp 0.783
rs 0.6314
c 0
b 0
f 0

83 Methods

Rating   Name   Duplication   Size   Complexity  
A getDateArithmeticIntervalExpression() 0 8 2
A getTableWhereClause() 6 15 2
A getLocateExpression() 0 9 2
A supportsPartialIndexes() 0 3 1
A getIdentitySequenceName() 0 3 1
A getListSequencesSQL() 0 3 1
A supportsSequences() 0 3 1
A getRegexpExpression() 0 3 1
A getDefaultSchemaName() 0 3 1
A getSubstringExpression() 7 7 2
A getDateDiffExpression() 0 3 1
A supportsSchemas() 0 3 1
A getDisallowDatabaseConnectionsSQL() 0 3 1
A getListTableForeignKeysSQL() 0 9 1
A getListTablesSQL() 0 3 1
B getListTableColumnsSQL() 0 27 1
A getCreateViewSQL() 0 3 1
A usesSequenceEmulatedIdentityColumns() 0 3 1
A getListTableIndexesSQL() 0 10 1
A getListNamespacesSQL() 0 3 1
A getNowExpression() 0 3 1
A getListTableConstraintsSQL() 0 13 1
A getDropViewSQL() 0 3 1
A getListViewsSQL() 0 3 1
A getCreateDatabaseSQL() 0 3 1
A supportsIdentityColumns() 0 3 1
A supportsCommentOnStatement() 0 3 1
A setUseBooleanTrueFalseStrings() 0 3 1
C getAdvancedForeignKeyOptionsSQL() 0 25 8
A hasNativeGuidType() 0 3 1
A getListDatabasesSQL() 0 3 1
A prefersSequences() 0 3 1
A getCloseActiveDatabaseConnectionsSQL() 0 5 1
A convertFromBoolean() 0 7 2
A getAlterSequenceSQL() 0 5 1
A getBigIntTypeDeclarationSQL() 0 7 2
A getIntegerTypeDeclarationSQL() 0 7 2
A getCommentOnColumnSQL() 8 8 2
A convertBooleansToDatabaseValue() 0 10 3
A getCreateSequenceSQL() 7 7 1
A getBinaryTypeDeclarationSQLSnippet() 0 3 1
A getGuidExpression() 0 3 1
A getVarcharTypeDeclarationSQLSnippet() 0 4 4
C isUnchangedBinaryColumn() 0 25 8
A _getCommonIntegerTypeDeclarationSQL() 0 3 1
A isNumericType() 0 3 2
A getReadLockSQL() 0 3 1
A getGuidTypeDeclarationSQL() 0 3 1
A getRenameIndexSQL() 8 8 2
A getDropForeignKeySQL() 0 3 1
A getName() 0 3 1
A getTimeTypeDeclarationSQL() 0 3 1
A quoteStringLiteral() 0 5 1
A getCreateSchemaSQL() 0 3 1
A getDropSequenceSQL() 0 7 2
A getBinaryMaxLength() 0 3 1
A doConvertBooleans() 0 11 3
A getReservedKeywordsClass() 0 3 1
A getDateTimeTzTypeDeclarationSQL() 0 3 1
A getSmallIntTypeDeclarationSQL() 0 3 1
A getDateTypeDeclarationSQL() 0 3 1
A getDateTimeTzFormatString() 0 3 1
C _getCreateTableSQL() 14 26 8
A getBlobTypeDeclarationSQL() 0 3 1
A getEmptyIdentityInsertSQL() 0 3 1
A getDefaultValueDeclarationSQL() 0 7 2
A getSequenceNextValSQL() 0 3 1
A getSQLResultCasing() 0 3 1
B initializeDoctrineTypeMappings() 42 42 1
A getSetTransactionIsolationSQL() 0 4 1
F getAlterTableSQL() 37 130 27
A getVarcharMaxLength() 0 3 1
A getSequenceCacheSQL() 0 7 2
A convertBooleans() 0 14 4
A isSerialField() 0 4 3
A getClobTypeDeclarationSQL() 0 3 1
A getTruncateTableSQL() 0 10 2
A getBooleanTypeDeclarationSQL() 0 3 1
A getBinaryDefaultLength() 0 3 1
A getDateTimeTypeDeclarationSQL() 0 3 1
B typeChangeBreaksDefaultValue() 0 12 5
C convertSingleBooleanValue() 6 26 8
A getSequenceMetadataSQL() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PostgreSqlPlatform 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 PostgreSqlPlatform, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Platforms;
21
22
use Doctrine\DBAL\Schema\Column;
23
use Doctrine\DBAL\Schema\ColumnDiff;
24
use Doctrine\DBAL\Schema\Identifier;
25
use Doctrine\DBAL\Schema\Index;
26
use Doctrine\DBAL\Schema\Sequence;
27
use Doctrine\DBAL\Schema\TableDiff;
28
use Doctrine\DBAL\Types\BinaryType;
29
use Doctrine\DBAL\Types\BigIntType;
30
use Doctrine\DBAL\Types\BlobType;
31
use Doctrine\DBAL\Types\IntegerType;
32
use Doctrine\DBAL\Types\Type;
33
34
/**
35
 * PostgreSqlPlatform.
36
 *
37
 * @since  2.0
38
 * @author Roman Borschel <[email protected]>
39
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
40
 * @author Benjamin Eberlei <[email protected]>
41
 * @todo   Rename: PostgreSQLPlatform
42
 */
43
class PostgreSqlPlatform extends AbstractPlatform
44
{
45
    /**
46
     * @var bool
47
     */
48
    private $useBooleanTrueFalseStrings = true;
49
50
    /**
51
     * @var array PostgreSQL booleans literals
52
     */
53
    private $booleanLiterals = [
54
        'true' => [
55
            't',
56
            'true',
57
            'y',
58
            'yes',
59
            'on',
60
            '1'
61
        ],
62
        'false' => [
63
            'f',
64
            'false',
65
            'n',
66
            'no',
67
            'off',
68
            '0'
69
        ]
70
    ];
71
72
    /**
73
     * PostgreSQL has different behavior with some drivers
74
     * with regard to how booleans have to be handled.
75
     *
76
     * Enables use of 'true'/'false' or otherwise 1 and 0 instead.
77
     *
78
     * @param bool $flag
79
     */
80 10
    public function setUseBooleanTrueFalseStrings($flag)
81
    {
82 10
        $this->useBooleanTrueFalseStrings = (bool) $flag;
83 10
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88 5 View Code Duplication
    public function getSubstringExpression($value, $from, $length = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
89
    {
90 5
        if ($length === null) {
91 5
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
92
        }
93
94 5
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
95
    }
96
97
    /**
98
     * {@inheritDoc}
99
     */
100
    public function getNowExpression()
101
    {
102
        return 'LOCALTIMESTAMP(0)';
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 5
    public function getRegexpExpression()
109
    {
110 5
        return 'SIMILAR TO';
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116
    public function getLocateExpression($str, $substr, $startPos = false)
117
    {
118
        if ($startPos !== false) {
119
            $str = $this->getSubstringExpression($str, $startPos);
120
121
            return 'CASE WHEN (POSITION('.$substr.' IN '.$str.') = 0) THEN 0 ELSE (POSITION('.$substr.' IN '.$str.') + '.($startPos-1).') END';
122
        }
123
124
        return 'POSITION('.$substr.' IN '.$str.')';
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
131
    {
132
        if (self::DATE_INTERVAL_UNIT_QUARTER === $unit) {
133
            $interval *= 3;
134
            $unit = self::DATE_INTERVAL_UNIT_MONTH;
135
        }
136
137
        return "(" . $date ." " . $operator . " (" . $interval . " || ' " . $unit . "')::interval)";
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143
    public function getDateDiffExpression($date1, $date2)
144
    {
145
        return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))';
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151 5
    public function supportsSequences()
152
    {
153 5
        return true;
154
    }
155
156
    /**
157
     * {@inheritDoc}
158
     */
159
    public function supportsSchemas()
160
    {
161
        return true;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function getDefaultSchemaName()
168
    {
169
        return 'public';
170
    }
171
172
    /**
173
     * {@inheritDoc}
174
     */
175 5
    public function supportsIdentityColumns()
176
    {
177 5
        return true;
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 42
    public function supportsPartialIndexes()
184
    {
185 42
        return true;
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191 5
    public function usesSequenceEmulatedIdentityColumns()
192
    {
193 5
        return true;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199 5
    public function getIdentitySequenceName($tableName, $columnName)
200
    {
201 5
        return $tableName . '_' . $columnName . '_seq';
202
    }
203
204
    /**
205
     * {@inheritDoc}
206
     */
207 75
    public function supportsCommentOnStatement()
208
    {
209 75
        return true;
210
    }
211
212
    /**
213
     * {@inheritDoc}
214
     */
215 5
    public function prefersSequences()
216
    {
217 5
        return true;
218
    }
219
220
    /**
221
     * {@inheritDoc}
222
     */
223 225
    public function hasNativeGuidType()
224
    {
225 225
        return true;
226
    }
227
228
    /**
229
     * {@inheritDoc}
230
     */
231
    public function getListDatabasesSQL()
232
    {
233
        return 'SELECT datname FROM pg_database';
234
    }
235
236
    /**
237
     * {@inheritDoc}
238
     */
239
    public function getListNamespacesSQL()
240
    {
241
        return "SELECT schema_name AS nspname
242
                FROM   information_schema.schemata
243
                WHERE  schema_name NOT LIKE 'pg\_%'
244
                AND    schema_name != 'information_schema'";
245
    }
246
247
    /**
248
     * {@inheritDoc}
249
     */
250
    public function getListSequencesSQL($database)
251
    {
252
        return "SELECT sequence_name AS relname,
253
                       sequence_schema AS schemaname
254
                FROM   information_schema.sequences
255
                WHERE  sequence_schema NOT LIKE 'pg\_%'
256
                AND    sequence_schema != 'information_schema'";
257
    }
258
259
    /**
260
     * {@inheritDoc}
261
     */
262
    public function getListTablesSQL()
263
    {
264
        return "SELECT quote_ident(table_name) AS table_name,
265
                       table_schema AS schema_name
266
                FROM   information_schema.tables
267
                WHERE  table_schema NOT LIKE 'pg\_%'
268
                AND    table_schema != 'information_schema'
269
                AND    table_name != 'geometry_columns'
270
                AND    table_name != 'spatial_ref_sys'
271
                AND    table_type != 'VIEW'";
272
    }
273
274
    /**
275
     * {@inheritDoc}
276
     */
277
    public function getListViewsSQL($database)
278
    {
279
        return 'SELECT quote_ident(table_name) AS viewname,
280
                       table_schema AS schemaname,
281
                       view_definition AS definition
282
                FROM   information_schema.views
283
                WHERE  view_definition IS NOT NULL';
284
    }
285
286
    /**
287
     * {@inheritDoc}
288
     */
289 10
    public function getListTableForeignKeysSQL($table, $database = null)
0 ignored issues
show
Unused Code introduced by
The parameter $database 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

289
    public function getListTableForeignKeysSQL($table, /** @scrutinizer ignore-unused */ $database = null)

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...
290
    {
291
        return "SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
292
                  FROM pg_catalog.pg_constraint r
293
                  WHERE r.conrelid =
294
                  (
295
                      SELECT c.oid
296
                      FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
297 10
                      WHERE " .$this->getTableWhereClause($table) ." AND n.oid = c.relnamespace
298
                  )
299
                  AND r.contype = 'f'";
300
    }
301
302
    /**
303
     * {@inheritDoc}
304
     */
305
    public function getCreateViewSQL($name, $sql)
306
    {
307
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
308
    }
309
310
    /**
311
     * {@inheritDoc}
312
     */
313
    public function getDropViewSQL($name)
314
    {
315
        return 'DROP VIEW '. $name;
316
    }
317
318
    /**
319
     * {@inheritDoc}
320
     */
321 5
    public function getListTableConstraintsSQL($table)
322
    {
323 5
        $table = new Identifier($table);
324 5
        $table = $this->quoteStringLiteral($table->getName());
325
326
        return "SELECT
327
                    quote_ident(relname) as relname
328
                FROM
329
                    pg_class
330
                WHERE oid IN (
331
                    SELECT indexrelid
332
                    FROM pg_index, pg_class
333 5
                    WHERE pg_class.relname = $table
334
                        AND pg_class.oid = pg_index.indrelid
335
                        AND (indisunique = 't' OR indisprimary = 't')
336
                        )";
337
    }
338
339
    /**
340
     * {@inheritDoc}
341
     *
342
     * @license New BSD License
343
     * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
344
     */
345 10
    public function getListTableIndexesSQL($table, $currentDatabase = null)
346
    {
347
        return "SELECT quote_ident(relname) as relname, pg_index.indisunique, pg_index.indisprimary,
348
                       pg_index.indkey, pg_index.indrelid,
349
                       pg_get_expr(indpred, indrelid) AS where
350
                 FROM pg_class, pg_index
351
                 WHERE oid IN (
352
                    SELECT indexrelid
353
                    FROM pg_index si, pg_class sc, pg_namespace sn
354 10
                    WHERE " . $this->getTableWhereClause($table, 'sc', 'sn')." AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid
355
                 ) AND pg_index.indexrelid = oid";
356
    }
357
358
    /**
359
     * @param string $table
360
     * @param string $classAlias
361
     * @param string $namespaceAlias
362
     *
363
     * @return string
364
     */
365 30
    private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n')
366
    {
367 30
        $whereClause = $namespaceAlias.".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND ";
368 30 View Code Duplication
        if (strpos($table, ".") !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
369 15
            list($schema, $table) = explode(".", $table);
370 15
            $schema = $this->quoteStringLiteral($schema);
371
        } else {
372 15
            $schema = "ANY(string_to_array((select replace(replace(setting,'\"\$user\"',user),' ','') from pg_catalog.pg_settings where name = 'search_path'),','))";
373
        }
374
375 30
        $table = new Identifier($table);
376 30
        $table = $this->quoteStringLiteral($table->getName());
377 30
        $whereClause .= "$classAlias.relname = " . $table . " AND $namespaceAlias.nspname = $schema";
378
379 30
        return $whereClause;
380
    }
381
382
    /**
383
     * {@inheritDoc}
384
     */
385 10
    public function getListTableColumnsSQL($table, $database = null)
386
    {
387
        return "SELECT
388
                    a.attnum,
389
                    quote_ident(a.attname) AS field,
390
                    t.typname AS type,
391
                    format_type(a.atttypid, a.atttypmod) AS complete_type,
392
                    (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type,
393
                    (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM
394
                      pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type,
395
                    a.attnotnull AS isnotnull,
396
                    (SELECT 't'
397
                     FROM pg_index
398
                     WHERE c.oid = pg_index.indrelid
399
                        AND pg_index.indkey[0] = a.attnum
400
                        AND pg_index.indisprimary = 't'
401
                    ) AS pri,
402
                    (SELECT pg_get_expr(adbin, adrelid)
403
                     FROM pg_attrdef
404
                     WHERE c.oid = pg_attrdef.adrelid
405
                        AND pg_attrdef.adnum=a.attnum
406
                    ) AS default,
407
                    (SELECT pg_description.description
408
                        FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid
409
                    ) AS comment
410
                    FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n
411 10
                    WHERE ".$this->getTableWhereClause($table, 'c', 'n') ."
412
                        AND a.attnum > 0
413
                        AND a.attrelid = c.oid
414
                        AND a.atttypid = t.oid
415
                        AND n.oid = c.relnamespace
416
                    ORDER BY a.attnum";
417
    }
418
419
    /**
420
     * {@inheritDoc}
421
     */
422 5
    public function getCreateDatabaseSQL($name)
423
    {
424 5
        return 'CREATE DATABASE ' . $name;
425
    }
426
427
    /**
428
     * Returns the SQL statement for disallowing new connections on the given database.
429
     *
430
     * This is useful to force DROP DATABASE operations which could fail because of active connections.
431
     *
432
     * @param string $database The name of the database to disallow new connections for.
433
     *
434
     * @return string
435
     */
436 5
    public function getDisallowDatabaseConnectionsSQL($database)
437
    {
438 5
        return "UPDATE pg_database SET datallowconn = 'false' WHERE datname = '$database'";
439
    }
440
441
    /**
442
     * Returns the SQL statement for closing currently active connections on the given database.
443
     *
444
     * This is useful to force DROP DATABASE operations which could fail because of active connections.
445
     *
446
     * @param string $database The name of the database to close currently active connections for.
447
     *
448
     * @return string
449
     */
450 4
    public function getCloseActiveDatabaseConnectionsSQL($database)
451
    {
452 4
        $database = $this->quoteStringLiteral($database);
453
454 4
        return "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = $database";
455
    }
456
457
    /**
458
     * {@inheritDoc}
459
     */
460 25
    public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
461
    {
462 25
        $query = '';
463
464 25
        if ($foreignKey->hasOption('match')) {
465 5
            $query .= ' MATCH ' . $foreignKey->getOption('match');
466
        }
467
468 25
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
469
470 25
        if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
471 5
            $query .= ' DEFERRABLE';
472
        } else {
473 25
            $query .= ' NOT DEFERRABLE';
474
        }
475
476 25
        if (($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false)
477 25
            || ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false)
478
        ) {
479 5
            $query .= ' INITIALLY DEFERRED';
480
        } else {
481 25
            $query .= ' INITIALLY IMMEDIATE';
482
        }
483
484 25
        return $query;
485
    }
486
487
    /**
488
     * {@inheritDoc}
489
     */
490 90
    public function getAlterTableSQL(TableDiff $diff)
491
    {
492 90
        $sql = [];
493 90
        $commentsSQL = [];
494 90
        $columnSql = [];
495
496 90
        foreach ($diff->addedColumns as $column) {
497 20
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
498
                continue;
499
            }
500
501 20
            $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
502 20
            $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
503
504 20
            $comment = $this->getColumnComment($column);
505
506 20 View Code Duplication
            if (null !== $comment && '' !== $comment) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
507 5
                $commentsSQL[] = $this->getCommentOnColumnSQL(
508 5
                    $diff->getName($this)->getQuotedName($this),
509 5
                    $column->getQuotedName($this),
510 20
                    $comment
511
                );
512
            }
513
        }
514
515 90
        foreach ($diff->removedColumns as $column) {
516 20
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
517
                continue;
518
            }
519
520 20
            $query = 'DROP ' . $column->getQuotedName($this);
521 20
            $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
522
        }
523
524 90
        foreach ($diff->changedColumns as $columnDiff) {
525
            /** @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */
526 50
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
527
                continue;
528
            }
529
530 50
            if ($this->isUnchangedBinaryColumn($columnDiff)) {
531 5
                continue;
532
            }
533
534 45
            $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this);
535 45
            $column = $columnDiff->column;
536
537 45
            if ($columnDiff->hasChanged('type') || $columnDiff->hasChanged('precision') || $columnDiff->hasChanged('scale') || $columnDiff->hasChanged('fixed')) {
538 20
                $type = $column->getType();
539
540
                // SERIAL/BIGSERIAL are not "real" types and we can't alter a column to that type
541 20
                $columnDefinition = $column->toArray();
542 20
                $columnDefinition['autoincrement'] = false;
543
544
                // here was a server version check before, but DBAL API does not support this anymore.
545 20
                $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this);
546 20
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
547
            }
548
549 45
            if ($columnDiff->hasChanged('default') || $this->typeChangeBreaksDefaultValue($columnDiff)) {
550 10
                $defaultClause = null === $column->getDefault()
551 5
                    ? ' DROP DEFAULT'
552 10
                    : ' SET' . $this->getDefaultValueDeclarationSQL($column->toArray());
553 10
                $query = 'ALTER ' . $oldColumnName . $defaultClause;
554 10
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
555
            }
556
557 45
            if ($columnDiff->hasChanged('notnull')) {
558 10
                $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL';
559 10
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
560
            }
561
562 45
            if ($columnDiff->hasChanged('autoincrement')) {
563
                if ($column->getAutoincrement()) {
564
                    // add autoincrement
565
                    $seqName = $this->getIdentitySequenceName($diff->name, $oldColumnName);
566
567
                    $sql[] = "CREATE SEQUENCE " . $seqName;
568
                    $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->getName($this)->getQuotedName($this) . "))";
569
                    $query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')";
570
                    $sql[] = "ALTER TABLE " . $diff->getName($this)->getQuotedName($this) . " " . $query;
571
                } else {
572
                    // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have
573
                    $query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT";
574
                    $sql[] = "ALTER TABLE " . $diff->getName($this)->getQuotedName($this) . " " . $query;
575
                }
576
            }
577
578 45 View Code Duplication
            if ($columnDiff->hasChanged('comment')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
579 10
                $commentsSQL[] = $this->getCommentOnColumnSQL(
580 10
                    $diff->getName($this)->getQuotedName($this),
581 10
                    $column->getQuotedName($this),
582 10
                    $this->getColumnComment($column)
583
                );
584
            }
585
586 45
            if ($columnDiff->hasChanged('length')) {
587 5
                $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $column->getType()->getSQLDeclaration($column->toArray(), $this);
588 45
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query;
589
            }
590
        }
591
592 90 View Code Duplication
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
593 20
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
594
                continue;
595
            }
596
597 20
            $oldColumnName = new Identifier($oldColumnName);
598
599 20
            $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) .
600 20
                ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this);
601
        }
602
603 90
        $tableSql = [];
604
605 90 View Code Duplication
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
606 90
            $sql = array_merge($sql, $commentsSQL);
607
608 90
            if ($diff->newName !== false) {
609 10
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' RENAME TO ' . $diff->getNewName()->getQuotedName($this);
610
            }
611
612 90
            $sql = array_merge(
613 90
                $this->getPreAlterTableIndexForeignKeySQL($diff),
614 90
                $sql,
615 90
                $this->getPostAlterTableIndexForeignKeySQL($diff)
616
            );
617
        }
618
619 90
        return array_merge($sql, $tableSql, $columnSql);
620
    }
621
622
    /**
623
     * Checks whether a given column diff is a logically unchanged binary type column.
624
     *
625
     * Used to determine whether a column alteration for a binary type column can be skipped.
626
     * Doctrine's {@link \Doctrine\DBAL\Types\BinaryType} and {@link \Doctrine\DBAL\Types\BlobType}
627
     * are mapped to the same database column type on this platform as this platform
628
     * does not have a native VARBINARY/BINARY column type. Therefore the {@link \Doctrine\DBAL\Schema\Comparator}
629
     * might detect differences for binary type columns which do not have to be propagated
630
     * to database as there actually is no difference at database level.
631
     *
632
     * @param ColumnDiff $columnDiff The column diff to check against.
633
     *
634
     * @return boolean True if the given column diff is an unchanged binary type column, false otherwise.
635
     */
636 50
    private function isUnchangedBinaryColumn(ColumnDiff $columnDiff)
637
    {
638 50
        $columnType = $columnDiff->column->getType();
639
640 50
        if ( ! $columnType instanceof BinaryType && ! $columnType instanceof BlobType) {
641 45
            return false;
642
        }
643
644 5
        $fromColumn = $columnDiff->fromColumn instanceof Column ? $columnDiff->fromColumn : null;
645
646 5
        if ($fromColumn) {
647 5
            $fromColumnType = $fromColumn->getType();
648
649 5
            if ( ! $fromColumnType instanceof BinaryType && ! $fromColumnType instanceof BlobType) {
650
                return false;
651
            }
652
653 5
            return count(array_diff($columnDiff->changedProperties, ['type', 'length', 'fixed'])) === 0;
654
        }
655
656
        if ($columnDiff->hasChanged('type')) {
657
            return false;
658
        }
659
660
        return count(array_diff($columnDiff->changedProperties, ['length', 'fixed'])) === 0;
661
    }
662
663
    /**
664
     * {@inheritdoc}
665
     */
666 25 View Code Duplication
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
667
    {
668 25
        if (strpos($tableName, '.') !== false) {
669 10
            list($schema) = explode('.', $tableName);
670 10
            $oldIndexName = $schema . '.' . $oldIndexName;
671
        }
672
673 25
        return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)];
674
    }
675
676
    /**
677
     * {@inheritdoc}
678
     */
679 40 View Code Duplication
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
680
    {
681 40
        $tableName = new Identifier($tableName);
682 40
        $columnName = new Identifier($columnName);
683 40
        $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment);
684
685 40
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . "." . $columnName->getQuotedName($this) .
686 40
            " IS $comment";
687
    }
688
689
    /**
690
     * {@inheritDoc}
691
     */
692 10 View Code Duplication
    public function getCreateSequenceSQL(Sequence $sequence)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
693
    {
694 10
        return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
695 10
               ' INCREMENT BY ' . $sequence->getAllocationSize() .
696 10
               ' MINVALUE ' . $sequence->getInitialValue() .
697 10
               ' START ' . $sequence->getInitialValue() .
698 10
               $this->getSequenceCacheSQL($sequence);
699
    }
700
701
    /**
702
     * {@inheritDoc}
703
     */
704
    public function getAlterSequenceSQL(Sequence $sequence)
705
    {
706
        return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) .
707
               ' INCREMENT BY ' . $sequence->getAllocationSize() .
708
               $this->getSequenceCacheSQL($sequence);
709
    }
710
711
    /**
712
     * Cache definition for sequences
713
     *
714
     * @param Sequence $sequence
715
     *
716
     * @return string
717
     */
718 10
    private function getSequenceCacheSQL(Sequence $sequence)
719
    {
720 10
        if ($sequence->getCache() > 1) {
721 5
            return ' CACHE ' . $sequence->getCache();
722
        }
723
724 5
        return '';
725
    }
726
727
    /**
728
     * {@inheritDoc}
729
     */
730 5
    public function getDropSequenceSQL($sequence)
731
    {
732 5
        if ($sequence instanceof Sequence) {
733
            $sequence = $sequence->getQuotedName($this);
734
        }
735
736 5
        return 'DROP SEQUENCE ' . $sequence . ' CASCADE';
737
    }
738
739
    /**
740
     * {@inheritDoc}
741
     */
742 5
    public function getCreateSchemaSQL($schemaName)
743
    {
744 5
        return 'CREATE SCHEMA ' . $schemaName;
745
    }
746
747
    /**
748
     * {@inheritDoc}
749
     */
750 15
    public function getDropForeignKeySQL($foreignKey, $table)
751
    {
752 15
        return $this->getDropConstraintSQL($foreignKey, $table);
753
    }
754
755
    /**
756
     * {@inheritDoc}
757
     */
758 70
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
759
    {
760 70
        $queryFields = $this->getColumnDeclarationListSQL($columns);
761
762 70 View Code Duplication
        if (isset($options['primary']) && ! empty($options['primary'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
763 20
            $keyColumns = array_unique(array_values($options['primary']));
764 20
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
765
        }
766
767 70
        $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')';
768
769 70
        $sql[] = $query;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.
Loading history...
770
771 70 View Code Duplication
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
772 15
            foreach ($options['indexes'] as $index) {
773 15
                $sql[] = $this->getCreateIndexSQL($index, $tableName);
774
            }
775
        }
776
777 70 View Code Duplication
        if (isset($options['foreignKeys'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
778 5
            foreach ((array) $options['foreignKeys'] as $definition) {
779 5
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
780
            }
781
        }
782
783 70
        return $sql;
784
    }
785
786
    /**
787
     * Converts a single boolean value.
788
     *
789
     * First converts the value to its native PHP boolean type
790
     * and passes it to the given callback function to be reconverted
791
     * into any custom representation.
792
     *
793
     * @param mixed    $value    The value to convert.
794
     * @param callable $callback The callback function to use for converting the real boolean value.
795
     *
796
     * @return mixed
797
     * @throws \UnexpectedValueException
798
     */
799 160
    private function convertSingleBooleanValue($value, $callback)
800
    {
801 160
        if (null === $value) {
802 10
            return $callback(null);
803
        }
804
805 150
        if (is_bool($value) || is_numeric($value)) {
806 95
            return $callback($value ? true : false);
807
        }
808
809 55
        if (!is_string($value)) {
810
            return $callback(true);
811
        }
812
813
        /**
814
         * Better safe than sorry: http://php.net/in_array#106319
815
         */
816 55 View Code Duplication
        if (in_array(trim(strtolower($value)), $this->booleanLiterals['false'], true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
817 25
            return $callback(false);
818
        }
819
820 30 View Code Duplication
        if (in_array(trim(strtolower($value)), $this->booleanLiterals['true'], true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
821 25
            return $callback(true);
822
        }
823
824 5
        throw new \UnexpectedValueException("Unrecognized boolean literal '${value}'");
825
    }
826
827
    /**
828
     * Converts one or multiple boolean values.
829
     *
830
     * First converts the value(s) to their native PHP boolean type
831
     * and passes them to the given callback function to be reconverted
832
     * into any custom representation.
833
     *
834
     * @param mixed    $item     The value(s) to convert.
835
     * @param callable $callback The callback function to use for converting the real boolean value(s).
836
     *
837
     * @return mixed
838
     */
839
    private function doConvertBooleans($item, $callback)
840
    {
841 160
        if (is_array($item)) {
842
            foreach ($item as $key => $value) {
843
                $item[$key] = $this->convertSingleBooleanValue($value, $callback);
844
            }
845
846
            return $item;
847
        }
848
849 160
        return $this->convertSingleBooleanValue($item, $callback);
850
    }
851
852
    /**
853
     * {@inheritDoc}
854
     *
855
     * Postgres wants boolean values converted to the strings 'true'/'false'.
856
     */
857
    public function convertBooleans($item)
858
    {
859 90
        if ( ! $this->useBooleanTrueFalseStrings) {
860 10
            return parent::convertBooleans($item);
861
        }
862
863 80
        return $this->doConvertBooleans(
864 80
            $item,
865
            function ($boolean) {
866 80
                if (null === $boolean) {
867 5
                    return 'NULL';
868
                }
869
870 75
                return true === $boolean ? 'true' : 'false';
871 80
            }
872
        );
873
    }
874
875
    /**
876
     * {@inheritDoc}
877
     */
878
    public function convertBooleansToDatabaseValue($item)
879
    {
880 85
        if ( ! $this->useBooleanTrueFalseStrings) {
881 5
            return parent::convertBooleansToDatabaseValue($item);
882
        }
883
884 80
        return $this->doConvertBooleans(
885 80
            $item,
886
            function ($boolean) {
887 75
                return null === $boolean ? null : (int) $boolean;
888 80
            }
889
        );
890
    }
891
892
    /**
893
     * {@inheritDoc}
894
     */
895
    public function convertFromBoolean($item)
896
    {
897 75
        if (in_array(strtolower($item), $this->booleanLiterals['false'], true)) {
898 30
            return false;
899
        }
900
901 45
        return parent::convertFromBoolean($item);
902
    }
903
904
    /**
905
     * {@inheritDoc}
906
     */
907
    public function getSequenceNextValSQL($sequenceName)
908
    {
909 5
        return "SELECT NEXTVAL('" . $sequenceName . "')";
910
    }
911
912
    /**
913
     * {@inheritDoc}
914
     */
915
    public function getSetTransactionIsolationSQL($level)
916
    {
917
        return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
918 5
                . $this->_getTransactionIsolationLevelSQL($level);
919
    }
920
921
    /**
922
     * {@inheritDoc}
923
     */
924
    public function getBooleanTypeDeclarationSQL(array $field)
925
    {
926 5
        return 'BOOLEAN';
927
    }
928
929
    /**
930
     * {@inheritDoc}
931
     */
932
    public function getIntegerTypeDeclarationSQL(array $field)
933
    {
934 55
        if ( ! empty($field['autoincrement'])) {
935 25
            return 'SERIAL';
936
        }
937
938 35
        return 'INT';
939
    }
940
941
    /**
942
     * {@inheritDoc}
943
     */
944
    public function getBigIntTypeDeclarationSQL(array $field)
945
    {
946 10
        if ( ! empty($field['autoincrement'])) {
947 10
            return 'BIGSERIAL';
948
        }
949
950
        return 'BIGINT';
951
    }
952
953
    /**
954
     * {@inheritDoc}
955
     */
956
    public function getSmallIntTypeDeclarationSQL(array $field)
957
    {
958 3
        return 'SMALLINT';
959
    }
960
961
    /**
962
     * {@inheritDoc}
963
     */
964
    public function getGuidTypeDeclarationSQL(array $field)
965
    {
966 5
        return 'UUID';
967
    }
968
969
    /**
970
     * {@inheritDoc}
971
     */
972
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
973
    {
974
        return 'TIMESTAMP(0) WITHOUT TIME ZONE';
975
    }
976
977
    /**
978
     * {@inheritDoc}
979
     */
980
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
981
    {
982
        return 'TIMESTAMP(0) WITH TIME ZONE';
983
    }
984
985
    /**
986
     * {@inheritDoc}
987
     */
988
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
989
    {
990
        return 'DATE';
991
    }
992
993
    /**
994
     * {@inheritDoc}
995
     */
996
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
997
    {
998
        return 'TIME(0) WITHOUT TIME ZONE';
999
    }
1000
1001
    /**
1002
     * {@inheritDoc}
1003
     */
1004
    public function getGuidExpression()
1005
    {
1006
        return 'UUID_GENERATE_V4()';
1007
    }
1008
1009
    /**
1010
     * {@inheritDoc}
1011
     */
1012
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
1013
    {
1014
        return '';
1015
    }
1016
1017
    /**
1018
     * {@inheritDoc}
1019
     */
1020
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
1021
    {
1022 60
        return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
1023 60
                : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
1024
    }
1025
1026
    /**
1027
     * {@inheritdoc}
1028
     */
1029
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
1030
    {
1031 5
        return 'BYTEA';
1032
    }
1033
1034
    /**
1035
     * {@inheritDoc}
1036
     */
1037
    public function getClobTypeDeclarationSQL(array $field)
1038
    {
1039 7
        return 'TEXT';
1040
    }
1041
1042
    /**
1043
     * {@inheritDoc}
1044
     */
1045
    public function getName()
1046
    {
1047 10
        return 'postgresql';
1048
    }
1049
1050
    /**
1051
     * {@inheritDoc}
1052
     *
1053
     * PostgreSQL returns all column names in SQL result sets in lowercase.
1054
     */
1055
    public function getSQLResultCasing($column)
1056
    {
1057
        return strtolower($column);
1058
    }
1059
1060
    /**
1061
     * {@inheritDoc}
1062
     */
1063
    public function getDateTimeTzFormatString()
1064
    {
1065
        return 'Y-m-d H:i:sO';
1066
    }
1067
1068
    /**
1069
     * {@inheritDoc}
1070
     */
1071
    public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
1072
    {
1073
        return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
1074
    }
1075
1076
    /**
1077
     * {@inheritDoc}
1078
     */
1079
    public function getTruncateTableSQL($tableName, $cascade = false)
1080
    {
1081 5
        $tableIdentifier = new Identifier($tableName);
1082 5
        $sql = 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
1083
1084 5
        if ($cascade) {
1085
            $sql .= ' CASCADE';
1086
        }
1087
1088 5
        return $sql;
1089
    }
1090
1091
    /**
1092
     * {@inheritDoc}
1093
     */
1094
    public function getReadLockSQL()
1095
    {
1096
        return 'FOR SHARE';
1097
    }
1098
1099
    /**
1100
     * {@inheritDoc}
1101
     */
1102 View Code Duplication
    protected function initializeDoctrineTypeMappings()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1103
    {
1104 28
        $this->doctrineTypeMapping = [
1105
            'smallint'      => 'smallint',
1106
            'int2'          => 'smallint',
1107
            'serial'        => 'integer',
1108
            'serial4'       => 'integer',
1109
            'int'           => 'integer',
1110
            'int4'          => 'integer',
1111
            'integer'       => 'integer',
1112
            'bigserial'     => 'bigint',
1113
            'serial8'       => 'bigint',
1114
            'bigint'        => 'bigint',
1115
            'int8'          => 'bigint',
1116
            'bool'          => 'boolean',
1117
            'boolean'       => 'boolean',
1118
            'text'          => 'text',
1119
            'tsvector'      => 'text',
1120
            'varchar'       => 'string',
1121
            'interval'      => 'string',
1122
            '_varchar'      => 'string',
1123
            'char'          => 'string',
1124
            'bpchar'        => 'string',
1125
            'inet'          => 'string',
1126
            'date'          => 'date',
1127
            'datetime'      => 'datetime',
1128
            'timestamp'     => 'datetime',
1129
            'timestamptz'   => 'datetimetz',
1130
            'time'          => 'time',
1131
            'timetz'        => 'time',
1132
            'float'         => 'float',
1133
            'float4'        => 'float',
1134
            'float8'        => 'float',
1135
            'double'        => 'float',
1136
            'double precision' => 'float',
1137
            'real'          => 'float',
1138
            'decimal'       => 'decimal',
1139
            'money'         => 'decimal',
1140
            'numeric'       => 'decimal',
1141
            'year'          => 'date',
1142
            'uuid'          => 'guid',
1143
            'bytea'         => 'blob',
1144
        ];
1145 28
    }
1146
1147
    /**
1148
     * {@inheritDoc}
1149
     */
1150
    public function getVarcharMaxLength()
1151
    {
1152 60
        return 65535;
1153
    }
1154
1155
    /**
1156
     * {@inheritdoc}
1157
     */
1158
    public function getBinaryMaxLength()
1159
    {
1160 10
        return 0;
1161
    }
1162
1163
    /**
1164
     * {@inheritdoc}
1165
     */
1166
    public function getBinaryDefaultLength()
1167
    {
1168 10
        return 0;
1169
    }
1170
1171
    /**
1172
     * {@inheritDoc}
1173
     */
1174
    protected function getReservedKeywordsClass()
1175
    {
1176 51
        return Keywords\PostgreSQLKeywords::class;
1177
    }
1178
1179
    /**
1180
     * {@inheritDoc}
1181
     */
1182
    public function getBlobTypeDeclarationSQL(array $field)
1183
    {
1184 5
        return 'BYTEA';
1185
    }
1186
1187
    /**
1188
     * {@inheritdoc}
1189
     */
1190
    public function quoteStringLiteral($str)
1191
    {
1192 86
        $str = str_replace('\\', '\\\\', $str); // PostgreSQL requires backslashes to be escaped aswell.
1193
1194 86
        return parent::quoteStringLiteral($str);
1195
    }
1196
1197
    /**
1198
     * {@inheritdoc}
1199
     */
1200
    public function getDefaultValueDeclarationSQL($field)
1201
    {
1202 120
        if ($this->isSerialField($field)) {
1203 40
            return '';
1204
        }
1205
1206 85
        return parent::getDefaultValueDeclarationSQL($field);
1207
    }
1208
1209
    private function isSerialField(array $field) : bool
1210
    {
1211 120
        return $field['autoincrement'] ?? false === true && isset($field['type'])
1212
            && $this->isNumericType($field['type']);
1213
    }
1214
1215
    /**
1216
     * Check whether the type of a column is changed in a way that invalidates the default value for the column
1217
     *
1218
     * @param ColumnDiff $columnDiff
1219
     * @return bool
1220
     */
1221
    private function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff) : bool
1222
    {
1223 40
        if (! $columnDiff->fromColumn) {
1224 25
            return $columnDiff->hasChanged('type');
1225
        }
1226
1227 15
        $oldTypeIsNumeric = $this->isNumericType($columnDiff->fromColumn->getType());
1228 15
        $newTypeIsNumeric = $this->isNumericType($columnDiff->column->getType());
1229
1230
        // default should not be changed when switching between numeric types and the default comes from a sequence
1231 15
        return $columnDiff->hasChanged('type')
1232 15
            && ! ($oldTypeIsNumeric && $newTypeIsNumeric && $columnDiff->column->getAutoincrement());
1233
    }
1234
1235
    private function isNumericType(Type $type) : bool
1236
    {
1237 15
        return $type instanceof IntegerType || $type instanceof BigIntType;
1238
    }
1239
1240
    public function getSequenceMetadataSQL(string $sequenceName, string $schemaName) : string
1241
    {
1242 4
        return 'SELECT min_value, increment_by FROM ' . $this->quoteIdentifier($sequenceName);
1243
    }
1244
}
1245