Failed Conditions
Push — develop ( 152bc9...e39bc0 )
by Sergei
102:42 queued 37:39
created

SqlitePlatform::getForeignKeysInAlteredTable()   C

Complexity

Conditions 12
Paths 120

Size

Total Lines 51
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 12.0092

Importance

Changes 0
Metric Value
eloc 31
dl 0
loc 51
ccs 24
cts 25
cp 0.96
rs 6.8
c 0
b 0
f 0
cc 12
nc 120
nop 1
crap 12.0092

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Doctrine\DBAL\Platforms;
4
5
use Doctrine\DBAL\DBALException;
6
use Doctrine\DBAL\Schema\Column;
7
use Doctrine\DBAL\Schema\Constraint;
8
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
9
use Doctrine\DBAL\Schema\Identifier;
10
use Doctrine\DBAL\Schema\Index;
11
use Doctrine\DBAL\Schema\Table;
12
use Doctrine\DBAL\Schema\TableDiff;
13
use Doctrine\DBAL\TransactionIsolationLevel;
14
use Doctrine\DBAL\Types;
15
use function array_merge;
16
use function array_unique;
17
use function array_values;
18
use function implode;
19
use function is_numeric;
20
use function sprintf;
21
use function sqrt;
22
use function str_replace;
23
use function strlen;
24
use function strpos;
25
use function strtolower;
26
27
/**
28
 * The SqlitePlatform class describes the specifics and dialects of the SQLite
29
 * database platform.
30
 *
31
 * @todo   Rename: SQLitePlatform
32
 */
33
class SqlitePlatform extends AbstractPlatform
34
{
35
    /**
36
     * {@inheritDoc}
37
     */
38 23
    public function getRegexpExpression()
39
    {
40 23
        return 'REGEXP';
41
    }
42
43
    /**
44
     * {@inheritDoc}
45
     */
46
    public function getNowExpression($type = 'timestamp')
47
    {
48
        switch ($type) {
49
            case 'time':
50
                return 'time(\'now\')';
51
            case 'date':
52
                return 'date(\'now\')';
53
            case 'timestamp':
54
            default:
55
                return 'datetime(\'now\')';
56
        }
57
    }
58
59
    /**
60
     * {@inheritDoc}
61
     */
62 36
    public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false)
63
    {
64 36
        $trimChar = $char !== false ? (', ' . $char) : '';
65
66 36
        switch ($pos) {
67
            case TrimMode::LEADING:
68 9
                $trimFn = 'LTRIM';
69 9
                break;
70
71
            case TrimMode::TRAILING:
72 9
                $trimFn = 'RTRIM';
73 9
                break;
74
75
            default:
76 18
                $trimFn = 'TRIM';
77
        }
78
79 36
        return $trimFn . '(' . $str . $trimChar . ')';
80
    }
81
82
    /**
83
     * {@inheritDoc}
84
     *
85
     * SQLite only supports the 2 parameter variant of this function
86
     */
87 23
    public function getSubstringExpression($value, $position, $length = null)
88
    {
89 23
        if ($length !== null) {
90 23
            return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
91
        }
92
93 23
        return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
94
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99 1
    public function getLocateExpression($str, $substr, $startPos = false)
100
    {
101 1
        if ($startPos === false) {
102 1
            return 'LOCATE(' . $str . ', ' . $substr . ')';
103
        }
104
105 1
        return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')';
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111 48
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
112
    {
113 48
        switch ($unit) {
114
            case DateIntervalUnit::SECOND:
115
            case DateIntervalUnit::MINUTE:
116
            case DateIntervalUnit::HOUR:
117 1
                return 'DATETIME(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')";
118
119
            default:
120 48
                switch ($unit) {
121
                    case DateIntervalUnit::WEEK:
122 1
                        $interval *= 7;
123 1
                        $unit      = DateIntervalUnit::DAY;
124 1
                        break;
125
126
                    case DateIntervalUnit::QUARTER:
127 1
                        $interval *= 3;
128 1
                        $unit      = DateIntervalUnit::MONTH;
129 1
                        break;
130
                }
131
132 48
                if (! is_numeric($interval)) {
133 24
                    $interval = "' || " . $interval . " || '";
134
                }
135
136 48
                return 'DATE(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')";
137
        }
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143 3
    public function getDateDiffExpression($date1, $date2)
144
    {
145 3
        return sprintf("JULIANDAY(%s, 'start of day') - JULIANDAY(%s, 'start of day')", $date1, $date2);
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151 23
    protected function _getTransactionIsolationLevelSQL($level)
152
    {
153 23
        switch ($level) {
154
            case TransactionIsolationLevel::READ_UNCOMMITTED:
155 23
                return 0;
156
            case TransactionIsolationLevel::READ_COMMITTED:
157
            case TransactionIsolationLevel::REPEATABLE_READ:
158
            case TransactionIsolationLevel::SERIALIZABLE:
159 23
                return 1;
160
            default:
161
                return parent::_getTransactionIsolationLevelSQL($level);
162
        }
163
    }
164
165
    /**
166
     * {@inheritDoc}
167
     */
168 23
    public function getSetTransactionIsolationSQL($level)
169
    {
170 23
        return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
171
    }
172
173
    /**
174
     * {@inheritDoc}
175
     */
176 24
    public function prefersIdentityColumns()
177
    {
178 24
        return true;
179
    }
180
181
    /**
182
     * {@inheritDoc}
183
     */
184 38
    public function getBooleanTypeDeclarationSQL(array $field)
185
    {
186 38
        return 'BOOLEAN';
187
    }
188
189
    /**
190
     * {@inheritDoc}
191
     */
192 660
    public function getIntegerTypeDeclarationSQL(array $field)
193
    {
194 660
        return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($field);
195
    }
196
197
    /**
198
     * {@inheritDoc}
199
     */
200 40
    public function getBigIntTypeDeclarationSQL(array $field)
201
    {
202
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT fields.
203 40
        if (! empty($field['autoincrement'])) {
204 25
            return $this->getIntegerTypeDeclarationSQL($field);
205
        }
206
207 38
        return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
208
    }
209
210
    /**
211
     * {@inheritDoc}
212
     */
213 46
    public function getTinyIntTypeDeclarationSql(array $field)
214
    {
215
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT fields.
216 46
        if (! empty($field['autoincrement'])) {
217 46
            return $this->getIntegerTypeDeclarationSQL($field);
218
        }
219
220 23
        return 'TINYINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
221
    }
222
223
    /**
224
     * {@inheritDoc}
225
     */
226 26
    public function getSmallIntTypeDeclarationSQL(array $field)
227
    {
228
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT fields.
229 26
        if (! empty($field['autoincrement'])) {
230 25
            return $this->getIntegerTypeDeclarationSQL($field);
231
        }
232
233 24
        return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
234
    }
235
236
    /**
237
     * {@inheritDoc}
238
     */
239 23
    public function getMediumIntTypeDeclarationSql(array $field)
240
    {
241
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT fields.
242 23
        if (! empty($field['autoincrement'])) {
243 23
            return $this->getIntegerTypeDeclarationSQL($field);
244
        }
245
246 23
        return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
247
    }
248
249
    /**
250
     * {@inheritDoc}
251
     */
252 22
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
253
    {
254 22
        return 'DATETIME';
255
    }
256
257
    /**
258
     * {@inheritDoc}
259
     */
260 19
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
261
    {
262 19
        return 'DATE';
263
    }
264
265
    /**
266
     * {@inheritDoc}
267
     */
268 18
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
269
    {
270 18
        return 'TIME';
271
    }
272
273
    /**
274
     * {@inheritDoc}
275
     */
276 660
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
277
    {
278
        // sqlite autoincrement is only possible for the primary key
279 660
        if (! empty($columnDef['autoincrement'])) {
280 238
            return ' PRIMARY KEY AUTOINCREMENT';
281
        }
282
283 580
        return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : '';
284
    }
285
286
    /**
287
     * {@inheritDoc}
288
     */
289 116
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
290
    {
291 116
        return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint(
292 116
            $foreignKey->getQuotedLocalColumns($this),
293 116
            str_replace('.', '__', $foreignKey->getQuotedForeignTableName($this)),
294 116
            $foreignKey->getQuotedForeignColumns($this),
295 116
            $foreignKey->getName(),
296 116
            $foreignKey->getOptions()
297
        ));
298
    }
299
300
    /**
301
     * {@inheritDoc}
302
     */
303 736
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
304
    {
305 736
        $tableName   = str_replace('.', '__', $tableName);
306 736
        $queryFields = $this->getColumnDeclarationListSQL($columns);
307
308 736
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
309
            foreach ($options['uniqueConstraints'] as $name => $definition) {
310
                $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
311
            }
312
        }
313
314 736
        $queryFields .= $this->getNonAutoincrementPrimaryKeyDefinition($columns, $options);
315
316 736
        if (isset($options['foreignKeys'])) {
317 713
            foreach ($options['foreignKeys'] as $foreignKey) {
318 116
                $queryFields .= ', ' . $this->getForeignKeyDeclarationSQL($foreignKey);
319
            }
320
        }
321
322 736
        $query = ['CREATE TABLE ' . $tableName . ' (' . $queryFields . ')'];
323
324 736
        if (isset($options['alter']) && $options['alter'] === true) {
325 289
            return $query;
326
        }
327
328 460
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
329 96
            foreach ($options['indexes'] as $indexDef) {
330 96
                $query[] = $this->getCreateIndexSQL($indexDef, $tableName);
331
            }
332
        }
333
334 460
        if (isset($options['unique']) && ! empty($options['unique'])) {
335
            foreach ($options['unique'] as $indexDef) {
336
                $query[] = $this->getCreateIndexSQL($indexDef, $tableName);
337
            }
338
        }
339
340 460
        return $query;
341
    }
342
343
    /**
344
     * Generate a PRIMARY KEY definition if no autoincrement value is used
345
     *
346
     * @param mixed[][] $columns
347
     * @param mixed[]   $options
348
     */
349 736
    private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $options) : string
350
    {
351 736
        if (empty($options['primary'])) {
352 368
            return '';
353
        }
354
355 368
        $keyColumns = array_unique(array_values($options['primary']));
356
357 368
        foreach ($keyColumns as $keyColumn) {
358 368
            if (! empty($columns[$keyColumn]['autoincrement'])) {
359 368
                return '';
360
            }
361
        }
362
363 270
        return ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
364
    }
365
366
    /**
367
     * {@inheritDoc}
368
     */
369 434
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
370
    {
371 434
        return $fixed
372 76
            ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
373 434
            : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
374
    }
375
376
    /**
377
     * {@inheritdoc}
378
     */
379 25
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
380
    {
381 25
        return 'BLOB';
382
    }
383
384
    /**
385
     * {@inheritdoc}
386
     */
387 23
    public function getBinaryMaxLength()
388
    {
389 23
        return 0;
390
    }
391
392
    /**
393
     * {@inheritdoc}
394
     */
395 47
    public function getBinaryDefaultLength()
396
    {
397 47
        return 0;
398
    }
399
400
    /**
401
     * {@inheritDoc}
402
     */
403 74
    public function getClobTypeDeclarationSQL(array $field)
404
    {
405 74
        return 'CLOB';
406
    }
407
408
    /**
409
     * {@inheritDoc}
410
     */
411 23
    public function getListTableConstraintsSQL($table)
412
    {
413 23
        $table = str_replace('.', '__', $table);
414
415 23
        return sprintf(
416 23
            "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = %s AND sql NOT NULL ORDER BY name",
417 23
            $this->quoteStringLiteral($table)
418
        );
419
    }
420
421
    /**
422
     * {@inheritDoc}
423
     */
424 108
    public function getListTableColumnsSQL($table, $currentDatabase = null)
425
    {
426 108
        $table = str_replace('.', '__', $table);
427
428 108
        return sprintf('PRAGMA table_info(%s)', $this->quoteStringLiteral($table));
429
    }
430
431
    /**
432
     * {@inheritDoc}
433
     */
434 101
    public function getListTableIndexesSQL($table, $currentDatabase = null)
435
    {
436 101
        $table = str_replace('.', '__', $table);
437
438 101
        return sprintf('PRAGMA index_list(%s)', $this->quoteStringLiteral($table));
439
    }
440
441
    /**
442
     * {@inheritDoc}
443
     */
444 132
    public function getListTablesSQL()
445
    {
446
        return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' "
447
             . 'UNION ALL SELECT name FROM sqlite_temp_master '
448 132
             . "WHERE type = 'table' ORDER BY name";
449
    }
450
451
    /**
452
     * {@inheritDoc}
453
     */
454 1
    public function getListViewsSQL($database)
455
    {
456 1
        return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
457
    }
458
459
    /**
460
     * {@inheritDoc}
461
     */
462 1
    public function getCreateViewSQL($name, $sql)
463
    {
464 1
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
465
    }
466
467
    /**
468
     * {@inheritDoc}
469
     */
470 1
    public function getDropViewSQL($name)
471
    {
472 1
        return 'DROP VIEW ' . $name;
473
    }
474
475
    /**
476
     * {@inheritDoc}
477
     */
478 116
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
479
    {
480 116
        $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
481
482 116
        $query .= ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false ? ' ' : ' NOT ') . 'DEFERRABLE';
483 116
        $query .= ' INITIALLY ' . ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false ? 'DEFERRED' : 'IMMEDIATE');
484
485 116
        return $query;
486
    }
487
488
    /**
489
     * {@inheritDoc}
490
     */
491 3
    public function supportsIdentityColumns()
492
    {
493 3
        return true;
494
    }
495
496
    /**
497
     * {@inheritDoc}
498
     */
499 70
    public function supportsColumnCollation()
500
    {
501 70
        return true;
502
    }
503
504
    /**
505
     * {@inheritDoc}
506
     */
507 828
    public function supportsInlineColumnComments()
508
    {
509 828
        return true;
510
    }
511
512
    /**
513
     * {@inheritDoc}
514
     */
515 136
    public function getName()
516
    {
517 136
        return 'sqlite';
518
    }
519
520
    /**
521
     * {@inheritDoc}
522
     */
523 31
    public function getTruncateTableSQL($tableName, $cascade = false)
524
    {
525 31
        $tableIdentifier = new Identifier($tableName);
526 31
        $tableName       = str_replace('.', '__', $tableIdentifier->getQuotedName($this));
527
528 31
        return 'DELETE FROM ' . $tableName;
529
    }
530
531
    /**
532
     * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction().
533
     *
534
     * @param int|float $value
535
     *
536
     * @return float
537
     */
538
    public static function udfSqrt($value)
539
    {
540
        return sqrt($value);
541
    }
542
543
    /**
544
     * User-defined function for Sqlite that implements MOD(a, b).
545
     *
546
     * @param int $a
547
     * @param int $b
548
     *
549
     * @return int
550
     */
551
    public static function udfMod($a, $b)
552
    {
553
        return $a % $b;
554
    }
555
556
    /**
557
     * @param string $str
558
     * @param string $substr
559
     * @param int    $offset
560
     *
561
     * @return int
562
     */
563 1
    public static function udfLocate($str, $substr, $offset = 0)
564
    {
565
        // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions.
566
        // So we have to make them compatible if an offset is given.
567 1
        if ($offset > 0) {
568 1
            $offset -= 1;
569
        }
570
571 1
        $pos = strpos($str, $substr, $offset);
572
573 1
        if ($pos !== false) {
574 1
            return $pos + 1;
575
        }
576
577 1
        return 0;
578
    }
579
580
    /**
581
     * {@inheritDoc}
582
     */
583
    public function getForUpdateSql()
584
    {
585
        return '';
586
    }
587
588
    /**
589
     * {@inheritDoc}
590
     */
591 170
    public function getInlineColumnCommentSQL($comment)
592
    {
593 170
        return '--' . str_replace("\n", "\n--", $comment) . "\n";
594
    }
595
596
    /**
597
     * {@inheritDoc}
598
     */
599 139
    protected function initializeDoctrineTypeMappings()
600
    {
601 139
        $this->doctrineTypeMapping = [
602
            'bigint'           => 'bigint',
603
            'bigserial'        => 'bigint',
604
            'blob'             => 'blob',
605
            'boolean'          => 'boolean',
606
            'char'             => 'string',
607
            'clob'             => 'text',
608
            'date'             => 'date',
609
            'datetime'         => 'datetime',
610
            'decimal'          => 'decimal',
611
            'double'           => 'float',
612
            'double precision' => 'float',
613
            'float'            => 'float',
614
            'image'            => 'string',
615
            'int'              => 'integer',
616
            'integer'          => 'integer',
617
            'longtext'         => 'text',
618
            'longvarchar'      => 'string',
619
            'mediumint'        => 'integer',
620
            'mediumtext'       => 'text',
621
            'ntext'            => 'string',
622
            'numeric'          => 'decimal',
623
            'nvarchar'         => 'string',
624
            'real'             => 'float',
625
            'serial'           => 'integer',
626
            'smallint'         => 'smallint',
627
            'string'           => 'string',
628
            'text'             => 'text',
629
            'time'             => 'time',
630
            'timestamp'        => 'datetime',
631
            'tinyint'          => 'boolean',
632
            'tinytext'         => 'text',
633
            'varchar'          => 'string',
634
            'varchar2'         => 'string',
635
        ];
636 139
    }
637
638
    /**
639
     * {@inheritDoc}
640
     */
641 930
    protected function getReservedKeywordsClass()
642
    {
643 930
        return Keywords\SQLiteKeywords::class;
644
    }
645
646
    /**
647
     * {@inheritDoc}
648
     */
649 289
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
650
    {
651 289
        if (! $diff->fromTable instanceof Table) {
652
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
653
        }
654
655 289
        $sql = [];
656 289
        foreach ($diff->fromTable->getIndexes() as $index) {
657 141
            if ($index->isPrimary()) {
658 95
                continue;
659
            }
660
661 70
            $sql[] = $this->getDropIndexSQL($index, $diff->name);
662
        }
663
664 289
        return $sql;
665
    }
666
667
    /**
668
     * {@inheritDoc}
669
     */
670 289
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
671
    {
672 289
        if (! $diff->fromTable instanceof Table) {
673
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
674
        }
675
676 289
        $sql       = [];
677 289
        $tableName = $diff->getNewName();
678 289
679 141
        if ($tableName === false) {
680 95
            $tableName = $diff->getName($this);
681
        }
682
683 116
        foreach ($this->getIndexesInAlteredTable($diff) as $index) {
684
            if ($index->isPrimary()) {
685
                continue;
686 289
            }
687
688
            $sql[] = $this->getCreateIndexSQL($index, $tableName->getQuotedName($this));
689
        }
690
691
        return $sql;
692 100
    }
693
694 100
    /**
695 24
     * {@inheritDoc}
696
     */
697
    protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string
698 100
    {
699
        if ($limit === null && $offset > 0) {
700
            $limit = -1;
701
        }
702
703
        return parent::doModifyLimitQuery($query, $limit, $offset);
704 8
    }
705
706 8
    /**
707
     * {@inheritDoc}
708
     */
709
    public function getBlobTypeDeclarationSQL(array $field)
710
    {
711
        return 'BLOB';
712 2
    }
713
714 2
    /**
715
     * {@inheritDoc}
716 2
     */
717
    public function getTemporaryTableName($tableName)
718
    {
719
        $tableName = str_replace('.', '__', $tableName);
720
721
        return $tableName;
722
    }
723
724
    /**
725
     * {@inheritDoc}
726
     *
727
     * Sqlite Platform emulates schema by underscoring each dot and generating tables
728
     * into the default database.
729
     *
730
     * This hack is implemented to be able to use SQLite as testdriver when
731
     * using schema supporting databases.
732
     */
733
    public function canEmulateSchemas()
734
    {
735
        return true;
736 235
    }
737
738 235
    /**
739
     * {@inheritDoc}
740
     */
741
    public function supportsForeignKeyConstraints()
742
    {
743
        return false;
744
    }
745
746
    /**
747
     * {@inheritDoc}
748
     */
749
    public function getCreatePrimaryKeySQL(Index $index, $table)
750
    {
751
        throw new DBALException('Sqlite platform does not support alter primary key.');
752 46
    }
753
754 46
    /**
755
     * {@inheritdoc}
756
     */
757
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
758
    {
759
        throw new DBALException('Sqlite platform does not support alter foreign key.');
760
    }
761
762
    /**
763
     * {@inheritdoc}
764
     */
765
    public function getDropForeignKeySQL($foreignKey, $table)
766
    {
767
        throw new DBALException('Sqlite platform does not support alter foreign key.');
768 23
    }
769
770 23
    /**
771
     * {@inheritDoc}
772
     */
773
    public function getCreateConstraintSQL(Constraint $constraint, $table)
774
    {
775
        throw new DBALException('Sqlite platform does not support alter constraint.');
776 759
    }
777
778 759
    /**
779
     * {@inheritDoc}
780 759
     */
781
    public function getCreateTableSQL(Table $table, $createFlags = null)
782
    {
783
        $createFlags = $createFlags ?? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS;
784
785
        return parent::getCreateTableSQL($table, $createFlags);
786 24
    }
787
788 24
    /**
789
     * {@inheritDoc}
790 24
     */
791
    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

791
    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...
792
    {
793
        $table = str_replace('.', '__', $table);
794
795
        return sprintf('PRAGMA foreign_key_list(%s)', $this->quoteStringLiteral($table));
796 364
    }
797
798 364
    /**
799 364
     * {@inheritDoc}
800 29
     */
801
    public function getAlterTableSQL(TableDiff $diff)
802
    {
803 335
        $sql = $this->getSimpleAlterTableSQL($diff);
804 335
        if ($sql !== false) {
0 ignored issues
show
introduced by
The condition $sql !== false is always false.
Loading history...
805 46
            return $sql;
806
        }
807
808 289
        $fromTable = $diff->fromTable;
809
        if (! $fromTable instanceof Table) {
810 289
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
811 289
        }
812 289
813 289
        $table = clone $fromTable;
814
815 289
        $columns        = [];
816 266
        $oldColumnNames = [];
817 266
        $newColumnNames = [];
818 266
        $columnSql      = [];
819
820
        foreach ($table->getColumns() as $columnName => $column) {
821 289
            $columnName                  = strtolower($columnName);
822 93
            $columns[$columnName]        = $column;
823
            $oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this);
824
        }
825
826 93
        foreach ($diff->removedColumns as $columnName => $column) {
827 93
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
828
                continue;
829
            }
830
831
            $columnName = strtolower($columnName);
832 93
            if (! isset($columns[$columnName])) {
833 93
                continue;
834 93
            }
835
836
            unset(
837
                $columns[$columnName],
838 289
                $oldColumnNames[$columnName],
839 115
                $newColumnNames[$columnName]
840
            );
841
        }
842
843 115
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
844 115
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
845 115
                continue;
846
            }
847
848 115
            $oldColumnName = strtolower($oldColumnName);
849
            if (isset($columns[$oldColumnName])) {
850 115
                unset($columns[$oldColumnName]);
851
            }
852
853
            $columns[strtolower($column->getName())] = $column;
854 115
855
            if (! isset($newColumnNames[$oldColumnName])) {
856
                continue;
857 289
            }
858 150
859
            $newColumnNames[$oldColumnName] = $column->getQuotedName($this);
860
        }
861
862 150
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
863 127
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
864
                continue;
865
            }
866 150
867
            if (isset($columns[$oldColumnName])) {
868 150
                unset($columns[$oldColumnName]);
869 23
            }
870
871
            $columns[strtolower($columnDiff->column->getName())] = $columnDiff->column;
872 127
873
            if (! isset($newColumnNames[$oldColumnName])) {
874
                continue;
875 289
            }
876 70
877
            $newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this);
878
        }
879
880 70
        foreach ($diff->addedColumns as $columnName => $column) {
881
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
882
                continue;
883 289
            }
884 289
885
            $columns[strtolower($columnName)] = $column;
886 289
        }
887 289
888
        $sql      = [];
889 289
        $tableSql = [];
890 289
891
        if (! $this->onSchemaAlterTable($diff, $tableSql)) {
892 289
            $dataTable = new Table('__temp__' . $table->getName());
893
894 289
            $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), [], $this->getForeignKeysInAlteredTable($diff), $table->getOptions());
895 289
            $newTable->addOption('alter', true);
896
897 289
            $sql = $this->getPreAlterTableIndexForeignKeySQL($diff);
898 289
            //$sql = array_merge($sql, $this->getCreateTableSQL($dataTable, 0));
899 289
            $sql[] = sprintf('CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', $dataTable->getQuotedName($this), implode(', ', $oldColumnNames), $table->getQuotedName($this));
900
            $sql[] = $this->getDropTableSQL($fromTable);
901 289
902 69
            $sql   = array_merge($sql, $this->getCreateTableSQL($newTable));
903 69
            $sql[] = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s', $newTable->getQuotedName($this), implode(', ', $newColumnNames), implode(', ', $oldColumnNames), $dataTable->getQuotedName($this));
904
            $sql[] = $this->getDropTableSQL($dataTable);
905
906 289
            $newName = $diff->getNewName();
907
908
            if ($newName !== false) {
909 289
                $sql[] = sprintf(
910
                    'ALTER TABLE %s RENAME TO %s',
911
                    $newTable->getQuotedName($this),
912
                    $newName->getQuotedName($this)
913
                );
914
            }
915 364
916
            $sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff));
917
        }
918 364
919 155
        return array_merge($sql, $tableSql, $columnSql);
920 63
    }
921 63
922 155
    /**
923
     * @return string[]|false
924 150
     */
925
    private function getSimpleAlterTableSQL(TableDiff $diff)
926
    {
927 5
        // Suppress changes on integer type autoincrement columns.
928 1
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
929
            if (! $columnDiff->fromColumn instanceof Column ||
930 1
                ! $columnDiff->column instanceof Column ||
931
                ! $columnDiff->column->getAutoincrement() ||
932
                ! $columnDiff->column->getType() instanceof Types\IntegerType
933 4
            ) {
934
                continue;
935 4
            }
936
937
            if (! $columnDiff->hasChanged('type') && $columnDiff->hasChanged('unsigned')) {
938
                unset($diff->changedColumns[$oldColumnName]);
939 4
940
                continue;
941
            }
942 364
943 249
            $fromColumnType = $columnDiff->fromColumn->getType();
944 145
945 364
            if (! ($fromColumnType instanceof Types\SmallIntType) && ! ($fromColumnType instanceof Types\BigIntType)) {
946
                continue;
947 289
            }
948
949
            unset($diff->changedColumns[$oldColumnName]);
950 75
        }
951
952 75
        if (! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes)
953 75
                || ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes)
954 75
                || ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes)
955
                || ! empty($diff->renamedIndexes)
956 75
        ) {
957 69
            return false;
958
        }
959
960
        $table = new Table($diff->name);
961 69
962 69
        $sql       = [];
963
        $tableSql  = [];
964 69
        $columnSql = [];
965 46
966 46
        foreach ($diff->addedColumns as $column) {
967 23
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
968 46
                continue;
969
            }
970
971 23
            $field = array_merge(['unique' => null, 'autoincrement' => null, 'default' => null], $column->toArray());
972 23
            $type  = $field['type'];
973 23
            switch (true) {
974
                case isset($field['columnDefinition']) || $field['autoincrement'] || $field['unique']:
975
                case $type instanceof Types\DateTimeType && $field['default'] === $this->getCurrentTimestampSQL():
976 23
                case $type instanceof Types\DateType && $field['default'] === $this->getCurrentDateSQL():
977
                case $type instanceof Types\TimeType && $field['default'] === $this->getCurrentTimeSQL():
978
                    return false;
979 29
            }
980 29
981 1
            $field['name'] = $column->getQuotedName($this);
982 1
            if ($type instanceof Types\StringType && $field['length'] === null) {
983
                $field['length'] = 255;
984
            }
985
986 29
            $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ADD COLUMN ' . $this->getColumnDeclarationSQL($field['name'], $field);
987
        }
988
989
        if (! $this->onSchemaAlterTable($diff, $tableSql)) {
990
            if ($diff->newName !== false) {
991
                $newTable = new Identifier($diff->newName);
0 ignored issues
show
Bug introduced by
It seems like $diff->newName can also be of type true; however, parameter $identifier of Doctrine\DBAL\Schema\Identifier::__construct() does only seem to accept string, 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

991
                $newTable = new Identifier(/** @scrutinizer ignore-type */ $diff->newName);
Loading history...
992 289
                $sql[]    = 'ALTER TABLE ' . $table->getQuotedName($this) . ' RENAME TO ' . $newTable->getQuotedName($this);
993
            }
994 289
        }
995
996 289
        return array_merge($sql, $tableSql, $columnSql);
997 266
    }
998
999
    /**
1000 289
     * @return string[]
1001 93
     */
1002 93
    private function getColumnNamesInAlteredTable(TableDiff $diff)
1003
    {
1004
        $columns = [];
1005
1006 93
        foreach ($diff->fromTable->getColumns() as $columnName => $column) {
0 ignored issues
show
Bug introduced by
The method getColumns() does not exist on null. ( Ignorable by Annotation )

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

1006
        foreach ($diff->fromTable->/** @scrutinizer ignore-call */ getColumns() as $columnName => $column) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1007
            $columns[strtolower($columnName)] = $column->getName();
1008
        }
1009 289
1010 115
        foreach ($diff->removedColumns as $columnName => $column) {
1011 115
            $columnName = strtolower($columnName);
1012 115
            if (! isset($columns[$columnName])) {
1013
                continue;
1014
            }
1015 289
1016 150
            unset($columns[$columnName]);
1017 150
        }
1018 150
1019
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
1020
            $columnName                          = $column->getName();
1021 289
            $columns[strtolower($oldColumnName)] = $columnName;
1022 70
            $columns[strtolower($columnName)]    = $columnName;
1023
        }
1024
1025 289
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
1026
            $columnName                          = $columnDiff->column->getName();
1027
            $columns[strtolower($oldColumnName)] = $columnName;
1028
            $columns[strtolower($columnName)]    = $columnName;
1029
        }
1030
1031 289
        foreach ($diff->addedColumns as $column) {
1032
            $columnName                       = $column->getName();
1033 289
            $columns[strtolower($columnName)] = $columnName;
1034 289
        }
1035
1036 289
        return $columns;
1037 141
    }
1038 70
1039 70
    /**
1040
     * @return Index[]
1041
     */
1042 24
    private function getIndexesInAlteredTable(TableDiff $diff)
1043
    {
1044
        $indexes     = $diff->fromTable->getIndexes();
1045 141
        $columnNames = $this->getColumnNamesInAlteredTable($diff);
1046 141
1047 141
        foreach ($indexes as $key => $index) {
1048 141
            foreach ($diff->renamedIndexes as $oldIndexName => $renamedIndex) {
1049 141
                if (strtolower($key) !== strtolower($oldIndexName)) {
1050 23
                    continue;
1051 23
                }
1052
1053 141
                unset($indexes[$key]);
1054 141
            }
1055 141
1056
            $changed      = false;
1057
            $indexColumns = [];
1058
            foreach ($index->getColumns() as $columnName) {
1059
                $normalizedColumnName = strtolower($columnName);
1060 141
                if (! isset($columnNames[$normalizedColumnName])) {
1061 141
                    unset($indexes[$key]);
1062
                    continue 2;
1063
                } else {
1064 23
                    $indexColumns[] = $columnNames[$normalizedColumnName];
1065
                    if ($columnName !== $columnNames[$normalizedColumnName]) {
1066
                        $changed = true;
1067 289
                    }
1068 24
                }
1069 24
            }
1070
1071
            if (! $changed) {
1072
                continue;
1073 24
            }
1074
1075
            $indexes[$key] = new Index($index->getName(), $indexColumns, $index->isUnique(), $index->isPrimary(), $index->getFlags());
1076 289
        }
1077 70
1078 70
        foreach ($diff->removedIndexes as $index) {
1079 70
            $indexName = strtolower($index->getName());
1080
            if (! strlen($indexName) || ! isset($indexes[$indexName])) {
1081 70
                continue;
1082
            }
1083
1084
            unset($indexes[$indexName]);
1085 289
        }
1086
1087
        foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) {
1088
            $indexName = strtolower($index->getName());
1089
            if (strlen($indexName)) {
1090
                $indexes[$indexName] = $index;
1091 289
            } else {
1092
                $indexes[] = $index;
1093 289
            }
1094 289
        }
1095
1096 289
        return $indexes;
1097 69
    }
1098 69
1099 69
    /**
1100 69
     * @return ForeignKeyConstraint[]
1101 69
     */
1102 23
    private function getForeignKeysInAlteredTable(TableDiff $diff)
1103 23
    {
1104
        $foreignKeys = $diff->fromTable->getForeignKeys();
1105 69
        $columnNames = $this->getColumnNamesInAlteredTable($diff);
1106 69
1107 69
        foreach ($foreignKeys as $key => $constraint) {
1108
            $changed      = false;
1109
            $localColumns = [];
1110
            foreach ($constraint->getLocalColumns() as $columnName) {
1111
                $normalizedColumnName = strtolower($columnName);
1112 69
                if (! isset($columnNames[$normalizedColumnName])) {
1113 69
                    unset($foreignKeys[$key]);
1114
                    continue 2;
1115
                } else {
1116 23
                    $localColumns[] = $columnNames[$normalizedColumnName];
1117
                    if ($columnName !== $columnNames[$normalizedColumnName]) {
1118
                        $changed = true;
1119 289
                    }
1120 23
                }
1121 23
            }
1122
1123
            if (! $changed) {
1124
                continue;
1125 23
            }
1126
1127
            $foreignKeys[$key] = new ForeignKeyConstraint($localColumns, $constraint->getForeignTableName(), $constraint->getForeignColumns(), $constraint->getName(), $constraint->getOptions());
1128 289
        }
1129 24
1130 24
        foreach ($diff->removedForeignKeys as $constraint) {
1131 23
            if (! $constraint instanceof ForeignKeyConstraint) {
1132
                $constraint = new Identifier($constraint);
1133 24
            }
1134
1135
            $constraintName = strtolower($constraint->getName());
1136
            if (! strlen($constraintName) || ! isset($foreignKeys[$constraintName])) {
1137 289
                continue;
1138
            }
1139
1140
            unset($foreignKeys[$constraintName]);
1141
        }
1142
1143 289
        foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) {
1144
            $constraintName = strtolower($constraint->getName());
1145 289
            if (strlen($constraintName)) {
1146
                $foreignKeys[$constraintName] = $constraint;
1147 289
            } else {
1148 141
                $foreignKeys[] = $constraint;
1149 116
            }
1150
        }
1151
1152 95
        return $foreignKeys;
1153
    }
1154
1155 289
    /**
1156
     * @return Index[]
1157
     */
1158
    private function getPrimaryIndexInAlteredTable(TableDiff $diff)
1159
    {
1160
        $primaryIndex = [];
1161
1162
        foreach ($this->getIndexesInAlteredTable($diff) as $index) {
1163
            if (! $index->isPrimary()) {
1164
                continue;
1165
            }
1166
1167
            $primaryIndex = [$index->getName() => $index];
1168
        }
1169
1170
        return $primaryIndex;
1171
    }
1172
}
1173