Passed
Push — master ( 047d0e...5cefa4 )
by Marco
06:53
created

lib/Doctrine/DBAL/Platforms/SqlitePlatform.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\DBALException;
23
use Doctrine\DBAL\Schema\Column;
24
use Doctrine\DBAL\Schema\TableDiff;
25
use Doctrine\DBAL\Schema\Table;
26
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
27
use Doctrine\DBAL\Schema\Index;
28
use Doctrine\DBAL\Schema\Identifier;
29
use Doctrine\DBAL\Schema\Constraint;
30
31
/**
32
 * The SqlitePlatform class describes the specifics and dialects of the SQLite
33
 * database platform.
34
 *
35
 * @since  2.0
36
 * @author Roman Borschel <[email protected]>
37
 * @author Benjamin Eberlei <[email protected]>
38
 * @author Martin Hasoň <[email protected]>
39
 * @todo   Rename: SQLitePlatform
40
 */
41
class SqlitePlatform extends AbstractPlatform
42
{
43
    /**
44
     * {@inheritDoc}
45
     */
46 1
    public function getRegexpExpression()
47
    {
48 1
        return 'REGEXP';
49
    }
50
51
    /**
52
     * {@inheritDoc}
53
     */
54 2
    public function getGuidExpression()
55
    {
56
        return "HEX(RANDOMBLOB(4)) || '-' || HEX(RANDOMBLOB(2)) || '-4' || "
57
            . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || "
58
            . "SUBSTR('89AB', 1 + (ABS(RANDOM()) % 4), 1) || "
59 2
            . "SUBSTR(HEX(RANDOMBLOB(2)), 2) || '-' || HEX(RANDOMBLOB(6))";
60
    }
61
62
    /**
63
     * {@inheritDoc}
64
     */
65
    public function getNowExpression($type = 'timestamp')
66
    {
67
        switch ($type) {
68
            case 'time':
69
                return 'time(\'now\')';
70
            case 'date':
71
                return 'date(\'now\')';
72
            case 'timestamp':
73
            default:
74
                return 'datetime(\'now\')';
75
        }
76
    }
77
78
    /**
79
     * {@inheritDoc}
80
     */
81 36
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
82
    {
83 36
        $trimChar = ($char != false) ? (', ' . $char) : '';
84
85 View Code Duplication
        switch ($pos) {
86 36
            case self::TRIM_LEADING:
87 9
                $trimFn = 'LTRIM';
88 9
                break;
89
90 27
            case self::TRIM_TRAILING:
91 9
                $trimFn = 'RTRIM';
92 9
                break;
93
94
            default:
95 18
                $trimFn = 'TRIM';
96
        }
97
98 36
        return $trimFn . '(' . $str . $trimChar . ')';
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     *
104
     * SQLite only supports the 2 parameter variant of this function
105
     */
106 1 View Code Duplication
    public function getSubstringExpression($value, $position, $length = null)
107
    {
108 1
        if ($length !== null) {
109 1
            return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
110
        }
111
112 1
        return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
113
    }
114
115
    /**
116
     * {@inheritDoc}
117
     */
118 1 View Code Duplication
    public function getLocateExpression($str, $substr, $startPos = false)
119
    {
120 1
        if ($startPos == false) {
121 1
            return 'LOCATE('.$str.', '.$substr.')';
122
        }
123
124 1
        return 'LOCATE('.$str.', '.$substr.', '.$startPos.')';
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130 1
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
131
    {
132
        switch ($unit) {
133 1
            case self::DATE_INTERVAL_UNIT_SECOND:
134 1
            case self::DATE_INTERVAL_UNIT_MINUTE:
135 1
            case self::DATE_INTERVAL_UNIT_HOUR:
136 1
                return "DATETIME(" . $date . ",'" . $operator . $interval . " " . $unit . "')";
137
138
            default:
139 View Code Duplication
                switch ($unit) {
140 1
                    case self::DATE_INTERVAL_UNIT_WEEK:
141 1
                        $interval *= 7;
142 1
                        $unit = self::DATE_INTERVAL_UNIT_DAY;
143 1
                        break;
144
145 1
                    case self::DATE_INTERVAL_UNIT_QUARTER:
146 1
                        $interval *= 3;
147 1
                        $unit = self::DATE_INTERVAL_UNIT_MONTH;
148 1
                        break;
149
                }
150
151 1
                return "DATE(" . $date . ",'" . $operator . $interval . " " . $unit . "')";
152
        }
153
    }
154
155
    /**
156
     * {@inheritDoc}
157
     */
158 1
    public function getDateDiffExpression($date1, $date2)
159
    {
160 1
        return 'ROUND(JULIANDAY('.$date1 . ')-JULIANDAY('.$date2.'))';
161
    }
162
163
    /**
164
     * {@inheritDoc}
165
     */
166 1 View Code Duplication
    protected function _getTransactionIsolationLevelSQL($level)
167
    {
168
        switch ($level) {
169 1
            case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
170 1
                return 0;
171 1
            case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
172 1
            case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
173 1
            case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
174 1
                return 1;
175
            default:
176
                return parent::_getTransactionIsolationLevelSQL($level);
177
        }
178
    }
179
180
    /**
181
     * {@inheritDoc}
182
     */
183 1
    public function getSetTransactionIsolationSQL($level)
184
    {
185 1
        return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
186
    }
187
188
    /**
189
     * {@inheritDoc}
190
     */
191 2
    public function prefersIdentityColumns()
192
    {
193 2
        return true;
194
    }
195
196
    /**
197
     * {@inheritDoc}
198
     */
199 16
    public function getBooleanTypeDeclarationSQL(array $field)
200
    {
201 16
        return 'BOOLEAN';
202
    }
203
204
    /**
205
     * {@inheritDoc}
206
     */
207 144
    public function getIntegerTypeDeclarationSQL(array $field)
208
    {
209 144
        return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($field);
210
    }
211
212
    /**
213
     * {@inheritDoc}
214
     */
215 18 View Code Duplication
    public function getBigIntTypeDeclarationSQL(array $field)
216
    {
217
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT fields.
218 18
        if ( ! empty($field['autoincrement'])) {
219 3
            return $this->getIntegerTypeDeclarationSQL($field);
220
        }
221
222 16
        return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
223
    }
224
225
    /**
226
     * {@inheritDoc}
227
     */
228 2 View Code Duplication
    public function getTinyIntTypeDeclarationSql(array $field)
229
    {
230
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT fields.
231 2
        if ( ! empty($field['autoincrement'])) {
232 2
            return $this->getIntegerTypeDeclarationSQL($field);
233
        }
234
235 1
        return 'TINYINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
236
    }
237
238
    /**
239
     * {@inheritDoc}
240
     */
241 4 View Code Duplication
    public function getSmallIntTypeDeclarationSQL(array $field)
242
    {
243
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT fields.
244 4
        if ( ! empty($field['autoincrement'])) {
245 3
            return $this->getIntegerTypeDeclarationSQL($field);
246
        }
247
248 2
        return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
249
    }
250
251
    /**
252
     * {@inheritDoc}
253
     */
254 1 View Code Duplication
    public function getMediumIntTypeDeclarationSql(array $field)
255
    {
256
        //  SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT fields.
257 1
        if ( ! empty($field['autoincrement'])) {
258 1
            return $this->getIntegerTypeDeclarationSQL($field);
259
        }
260
261 1
        return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
262
    }
263
264
    /**
265
     * {@inheritDoc}
266
     */
267 19
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
268
    {
269 19
        return 'DATETIME';
270
    }
271
272
    /**
273
     * {@inheritDoc}
274
     */
275 18
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
276
    {
277 18
        return 'DATE';
278
    }
279
280
    /**
281
     * {@inheritDoc}
282
     */
283 18
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
284
    {
285 18
        return 'TIME';
286
    }
287
288
    /**
289
     * {@inheritDoc}
290
     */
291 144
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
292
    {
293
        // sqlite autoincrement is implicit for integer PKs, but not when the field is unsigned
294 144
        if ( ! empty($columnDef['autoincrement'])) {
295 39
            return '';
296
        }
297
298 131
        return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : '';
299
    }
300
301
    /**
302
     * {@inheritDoc}
303
     */
304 6
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
305
    {
306 6
        return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint(
307 6
            $foreignKey->getQuotedLocalColumns($this),
308 6
            str_replace('.', '__', $foreignKey->getQuotedForeignTableName($this)),
309 6
            $foreignKey->getQuotedForeignColumns($this),
310 6
            $foreignKey->getName(),
311 6
            $foreignKey->getOptions()
312
        ));
313
    }
314
315
    /**
316
     * {@inheritDoc}
317
     */
318 147
    protected function _getCreateTableSQL($name, array $columns, array $options = array())
319
    {
320 147
        $name = str_replace('.', '__', $name);
321 147
        $queryFields = $this->getColumnDeclarationListSQL($columns);
322
323 147
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
324
            foreach ($options['uniqueConstraints'] as $name => $definition) {
325
                $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
326
            }
327
        }
328
329 147 View Code Duplication
        if (isset($options['primary']) && ! empty($options['primary'])) {
330 97
            $keyColumns = array_unique(array_values($options['primary']));
331 97
            $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')';
332
        }
333
334 147
        if (isset($options['foreignKeys'])) {
335 146
            foreach ($options['foreignKeys'] as $foreignKey) {
336 6
                $queryFields.= ', '.$this->getForeignKeyDeclarationSQL($foreignKey);
337
            }
338
        }
339
340 147
        $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
341
342 147
        if (isset($options['alter']) && true === $options['alter']) {
343 25
            return $query;
344
        }
345
346 135 View Code Duplication
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
347 8
            foreach ($options['indexes'] as $indexDef) {
348 8
                $query[] = $this->getCreateIndexSQL($indexDef, $name);
349
            }
350
        }
351
352 135 View Code Duplication
        if (isset($options['unique']) && ! empty($options['unique'])) {
353
            foreach ($options['unique'] as $indexDef) {
354
                $query[] = $this->getCreateIndexSQL($indexDef, $name);
355
            }
356
        }
357
358 135
        return $query;
359
    }
360
361
    /**
362
     * {@inheritDoc}
363
     */
364 80
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
365
    {
366 80
        return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
367 80
                : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
368
    }
369
370
    /**
371
     * {@inheritdoc}
372
     */
373 2
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
374
    {
375 2
        return 'BLOB';
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381 6
    public function getBinaryMaxLength()
382
    {
383 6
        return 0;
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389 3
    public function getBinaryDefaultLength()
390
    {
391 3
        return 0;
392
    }
393
394
    /**
395
     * {@inheritDoc}
396
     */
397 43
    public function getClobTypeDeclarationSQL(array $field)
398
    {
399 43
        return 'CLOB';
400
    }
401
402
    /**
403
     * {@inheritDoc}
404
     */
405 1
    public function getListTableConstraintsSQL($table)
406
    {
407 1
        $table = str_replace('.', '__', $table);
408 1
        $table = $this->quoteStringLiteral($table);
409
410 1
        return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = $table AND sql NOT NULL ORDER BY name";
411
    }
412
413
    /**
414
     * {@inheritDoc}
415
     */
416 39 View Code Duplication
    public function getListTableColumnsSQL($table, $currentDatabase = null)
417
    {
418 39
        $table = str_replace('.', '__', $table);
419 39
        $table = $this->quoteStringLiteral($table);
420
421 39
        return "PRAGMA table_info($table)";
422
    }
423
424
    /**
425
     * {@inheritDoc}
426
     */
427 32 View Code Duplication
    public function getListTableIndexesSQL($table, $currentDatabase = null)
428
    {
429 32
        $table = str_replace('.', '__', $table);
430 32
        $table = $this->quoteStringLiteral($table);
431
432 32
        return "PRAGMA index_list($table)";
433
    }
434
435
    /**
436
     * {@inheritDoc}
437
     */
438 14
    public function getListTablesSQL()
439
    {
440
        return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' "
441
             . "UNION ALL SELECT name FROM sqlite_temp_master "
442 14
             . "WHERE type = 'table' ORDER BY name";
443
    }
444
445
    /**
446
     * {@inheritDoc}
447
     */
448 1
    public function getListViewsSQL($database)
449
    {
450 1
        return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
451
    }
452
453
    /**
454
     * {@inheritDoc}
455
     */
456 1
    public function getCreateViewSQL($name, $sql)
457
    {
458 1
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
459
    }
460
461
    /**
462
     * {@inheritDoc}
463
     */
464 1
    public function getDropViewSQL($name)
465
    {
466 1
        return 'DROP VIEW '. $name;
467
    }
468
469
    /**
470
     * {@inheritDoc}
471
     */
472 6
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
473
    {
474 6
        $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
475
476 6
        $query .= (($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) ? ' ' : ' NOT ') . 'DEFERRABLE';
477 6
        $query .= ' INITIALLY ' . (($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) ? 'DEFERRED' : 'IMMEDIATE');
478
479 6
        return $query;
480
    }
481
482
    /**
483
     * {@inheritDoc}
484
     */
485 3
    public function supportsIdentityColumns()
486
    {
487 3
        return true;
488
    }
489
490
    /**
491
     * {@inheritDoc}
492
     */
493 1
    public function supportsColumnCollation()
494
    {
495 1
        return true;
496
    }
497
498
    /**
499
     * {@inheritDoc}
500
     */
501 151
    public function supportsInlineColumnComments()
502
    {
503 151
        return true;
504
    }
505
506
    /**
507
     * {@inheritDoc}
508
     */
509 62
    public function getName()
510
    {
511 62
        return 'sqlite';
512
    }
513
514
    /**
515
     * {@inheritDoc}
516
     */
517 12
    public function getTruncateTableSQL($tableName, $cascade = false)
518
    {
519 12
        $tableIdentifier = new Identifier($tableName);
520 12
        $tableName = str_replace('.', '__', $tableIdentifier->getQuotedName($this));
521
522 12
        return 'DELETE FROM ' . $tableName;
523
    }
524
525
    /**
526
     * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction().
527
     *
528
     * @param integer|float $value
529
     *
530
     * @return float
531
     */
532
    static public function udfSqrt($value)
533
    {
534
        return sqrt($value);
535
    }
536
537
    /**
538
     * User-defined function for Sqlite that implements MOD(a, b).
539
     *
540
     * @param integer $a
541
     * @param integer $b
542
     *
543
     * @return integer
544
     */
545
    static public function udfMod($a, $b)
546
    {
547
        return ($a % $b);
548
    }
549
550
    /**
551
     * @param string  $str
552
     * @param string  $substr
553
     * @param integer $offset
554
     *
555
     * @return integer
556
     */
557 1
    static public function udfLocate($str, $substr, $offset = 0)
558
    {
559
        // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions.
560
        // So we have to make them compatible if an offset is given.
561 1
        if ($offset > 0) {
562 1
            $offset -= 1;
563
        }
564
565 1
        $pos = strpos($str, $substr, $offset);
566
567 1
        if ($pos !== false) {
568 1
            return $pos + 1;
569
        }
570
571 1
        return 0;
572
    }
573
574
    /**
575
     * {@inheritDoc}
576
     */
577
    public function getForUpdateSql()
578
    {
579
        return '';
580
    }
581
582
    /**
583
     * {@inheritDoc}
584
     */
585 36
    public function getInlineColumnCommentSQL($comment)
586
    {
587 36
        return '--' . str_replace("\n", "\n--", $comment) . "\n";
588
    }
589
590
    /**
591
     * {@inheritDoc}
592
     */
593 7
    protected function initializeDoctrineTypeMappings()
594
    {
595 7
        $this->doctrineTypeMapping = array(
596
            'boolean'          => 'boolean',
597
            'tinyint'          => 'boolean',
598
            'smallint'         => 'smallint',
599
            'mediumint'        => 'integer',
600
            'int'              => 'integer',
601
            'integer'          => 'integer',
602
            'serial'           => 'integer',
603
            'bigint'           => 'bigint',
604
            'bigserial'        => 'bigint',
605
            'clob'             => 'text',
606
            'tinytext'         => 'text',
607
            'mediumtext'       => 'text',
608
            'longtext'         => 'text',
609
            'text'             => 'text',
610
            'varchar'          => 'string',
611
            'longvarchar'      => 'string',
612
            'varchar2'         => 'string',
613
            'nvarchar'         => 'string',
614
            'image'            => 'string',
615
            'ntext'            => 'string',
616
            'char'             => 'string',
617
            'date'             => 'date',
618
            'datetime'         => 'datetime',
619
            'timestamp'        => 'datetime',
620
            'time'             => 'time',
621
            'float'            => 'float',
622
            'double'           => 'float',
623
            'double precision' => 'float',
624
            'real'             => 'float',
625
            'decimal'          => 'decimal',
626
            'numeric'          => 'decimal',
627
            'blob'             => 'blob',
628
        );
629 7
    }
630
631
    /**
632
     * {@inheritDoc}
633
     */
634 49
    protected function getReservedKeywordsClass()
635
    {
636 49
        return 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords';
637
    }
638
639
    /**
640
     * {@inheritDoc}
641
     */
642 25
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
643
    {
644 25
        if ( ! $diff->fromTable instanceof Table) {
645
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
646
        }
647
648 25
        $sql = array();
649 25
        foreach ($diff->fromTable->getIndexes() as $index) {
650 9
            if ( ! $index->isPrimary()) {
651 4
                $sql[] = $this->getDropIndexSQL($index, $diff->name);
652
            }
653
        }
654
655 25
        return $sql;
656
    }
657
658
    /**
659
     * {@inheritDoc}
660
     */
661 25
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
662
    {
663 25
        if ( ! $diff->fromTable instanceof Table) {
664
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
665
        }
666
667 25
        $sql = array();
668 25
        $tableName = $diff->newName ? $diff->getNewName(): $diff->getName($this);
669 25
        foreach ($this->getIndexesInAlteredTable($diff) as $index) {
670 9
            if ($index->isPrimary()) {
671 7
                continue;
672
            }
673
674 6
            $sql[] = $this->getCreateIndexSQL($index, $tableName->getQuotedName($this));
675
        }
676
677 25
        return $sql;
678
    }
679
680
    /**
681
     * {@inheritDoc}
682
     */
683 11
    protected function doModifyLimitQuery($query, $limit, $offset)
684
    {
685 11
        if (null === $limit && null !== $offset) {
686 3
            return $query . ' LIMIT -1 OFFSET ' . $offset;
687
        }
688
689 9
        return parent::doModifyLimitQuery($query, $limit, $offset);
690
    }
691
692
    /**
693
     * {@inheritDoc}
694
     */
695 6
    public function getBlobTypeDeclarationSQL(array $field)
696
    {
697 6
        return 'BLOB';
698
    }
699
700
    /**
701
     * {@inheritDoc}
702
     */
703 2
    public function getTemporaryTableName($tableName)
704
    {
705 2
        $tableName = str_replace('.', '__', $tableName);
706
707 2
        return $tableName;
708
    }
709
710
    /**
711
     * {@inheritDoc}
712
     *
713
     * Sqlite Platform emulates schema by underscoring each dot and generating tables
714
     * into the default database.
715
     *
716
     * This hack is implemented to be able to use SQLite as testdriver when
717
     * using schema supporting databases.
718
     */
719
    public function canEmulateSchemas()
720
    {
721
        return true;
722
    }
723
724
    /**
725
     * {@inheritDoc}
726
     */
727 34
    public function supportsForeignKeyConstraints()
728
    {
729 34
        return false;
730
    }
731
732
    /**
733
     * {@inheritDoc}
734
     */
735
    public function getCreatePrimaryKeySQL(Index $index, $table)
736
    {
737
        throw new DBALException('Sqlite platform does not support alter primary key.');
738
    }
739
740
    /**
741
     * {@inheritdoc}
742
     */
743 2
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
744
    {
745 2
        throw new DBALException('Sqlite platform does not support alter foreign key.');
746
    }
747
748
    /**
749
     * {@inheritdoc}
750
     */
751
    public function getDropForeignKeySQL($foreignKey, $table)
752
    {
753
        throw new DBALException('Sqlite platform does not support alter foreign key.');
754
    }
755
756
    /**
757
     * {@inheritDoc}
758
     */
759 1
    public function getCreateConstraintSQL(Constraint $constraint, $table)
760
    {
761 1
        throw new DBALException('Sqlite platform does not support alter constraint.');
762
    }
763
764
    /**
765
     * {@inheritDoc}
766
     */
767 148
    public function getCreateTableSQL(Table $table, $createFlags = null)
768
    {
769 148
        $createFlags = null === $createFlags ? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS : $createFlags;
770
771 148
        return parent::getCreateTableSQL($table, $createFlags);
772
    }
773
774
    /**
775
     * {@inheritDoc}
776
     */
777 2 View Code Duplication
    public function getListTableForeignKeysSQL($table, $database = null)
0 ignored issues
show
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...
778
    {
779 2
        $table = str_replace('.', '__', $table);
780 2
        $table = $this->quoteStringLiteral($table);
781
782 2
        return "PRAGMA foreign_key_list($table)";
783
    }
784
785
    /**
786
     * {@inheritDoc}
787
     */
788 33
    public function getAlterTableSQL(TableDiff $diff)
789
    {
790 33
        $sql = $this->getSimpleAlterTableSQL($diff);
791 33
        if (false !== $sql) {
792 7
            return $sql;
793
        }
794
795 26
        $fromTable = $diff->fromTable;
796 26
        if ( ! $fromTable instanceof Table) {
797 1
            throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema');
798
        }
799
800 25
        $table = clone $fromTable;
801
802 25
        $columns = array();
803 25
        $oldColumnNames = array();
804 25
        $newColumnNames = array();
805 25
        $columnSql = array();
806
807 25
        foreach ($table->getColumns() as $columnName => $column) {
808 24
            $columnName = strtolower($columnName);
809 24
            $columns[$columnName] = $column;
810 24
            $oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this);
811
        }
812
813 25
        foreach ($diff->removedColumns as $columnName => $column) {
814 5
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
815
                continue;
816
            }
817
818 5
            $columnName = strtolower($columnName);
819 5
            if (isset($columns[$columnName])) {
820 5
                unset($columns[$columnName]);
821 5
                unset($oldColumnNames[$columnName]);
822 5
                unset($newColumnNames[$columnName]);
823
            }
824
        }
825
826 25
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
827 5
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
828
                continue;
829
            }
830
831 5
            $oldColumnName = strtolower($oldColumnName);
832 5
            if (isset($columns[$oldColumnName])) {
833 5
                unset($columns[$oldColumnName]);
834
            }
835
836 5
            $columns[strtolower($column->getName())] = $column;
837
838 5
            if (isset($newColumnNames[$oldColumnName])) {
839 5
                $newColumnNames[$oldColumnName] = $column->getQuotedName($this);
840
            }
841
        }
842
843 25
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
844 18
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
845
                continue;
846
            }
847
848 18
            if (isset($columns[$oldColumnName])) {
849 17
                unset($columns[$oldColumnName]);
850
            }
851
852 18
            $columns[strtolower($columnDiff->column->getName())] = $columnDiff->column;
853
854 18
            if (isset($newColumnNames[$oldColumnName])) {
855 17
                $newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this);
856
            }
857
        }
858
859 25
        foreach ($diff->addedColumns as $columnName => $column) {
860 4
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
861
                continue;
862
            }
863
864 4
            $columns[strtolower($columnName)] = $column;
865
        }
866
867 25
        $sql = array();
868 25
        $tableSql = array();
869 25
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
870 25
            $dataTable = new Table('__temp__'.$table->getName());
871
872 25
            $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions());
873 25
            $newTable->addOption('alter', true);
874
875 25
            $sql = $this->getPreAlterTableIndexForeignKeySQL($diff);
876
            //$sql = array_merge($sql, $this->getCreateTableSQL($dataTable, 0));
877 25
            $sql[] = sprintf('CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', $dataTable->getQuotedName($this), implode(', ', $oldColumnNames), $table->getQuotedName($this));
878 25
            $sql[] = $this->getDropTableSQL($fromTable);
879
880 25
            $sql = array_merge($sql, $this->getCreateTableSQL($newTable));
881 25
            $sql[] = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s', $newTable->getQuotedName($this), implode(', ', $newColumnNames), implode(', ', $oldColumnNames), $dataTable->getQuotedName($this));
882 25
            $sql[] = $this->getDropTableSQL($dataTable);
883
884 25
            if ($diff->newName && $diff->newName != $diff->name) {
885 3
                $renamedTable = $diff->getNewName();
886 3
                $sql[] = 'ALTER TABLE '.$newTable->getQuotedName($this).' RENAME TO '.$renamedTable->getQuotedName($this);
887
            }
888
889 25
            $sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff));
890
        }
891
892 25
        return array_merge($sql, $tableSql, $columnSql);
893
    }
894
895
    /**
896
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
897
     *
898
     * @return array|bool
899
     */
900 33
    private function getSimpleAlterTableSQL(TableDiff $diff)
901
    {
902
        // Suppress changes on integer type autoincrement columns.
903 33
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
904 23
            if ( ! $columnDiff->fromColumn instanceof Column ||
905 19
                ! $columnDiff->column instanceof Column ||
906 19
                ! $columnDiff->column->getAutoincrement() ||
907 5
                ! (string) $columnDiff->column->getType() === 'Integer'
908
            ) {
909 18
                continue;
910
            }
911
912 5
            if ( ! $columnDiff->hasChanged('type') && $columnDiff->hasChanged('unsigned')) {
913 1
                unset($diff->changedColumns[$oldColumnName]);
914
915 1
                continue;
916
            }
917
918 4
            $fromColumnType = (string) $columnDiff->fromColumn->getType();
919
920 4
            if ($fromColumnType === 'SmallInt' || $fromColumnType === 'BigInt') {
921 4
                unset($diff->changedColumns[$oldColumnName]);
922
            }
923
        }
924
925 33
        if ( ! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes)
926 28
                || ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes)
927 12
                || ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes)
928 12
                || ! empty($diff->renamedIndexes)
929
        ) {
930 25
            return false;
931
        }
932
933 8
        $table = new Table($diff->name);
934
935 8
        $sql = array();
936 8
        $tableSql = array();
937 8
        $columnSql = array();
938
939 8
        foreach ($diff->addedColumns as $column) {
940 2
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
941
                continue;
942
            }
943
944 2
            $field = array_merge(array('unique' => null, 'autoincrement' => null, 'default' => null), $column->toArray());
945 2
            $type = (string) $field['type'];
946
            switch (true) {
947 2
                case isset($field['columnDefinition']) || $field['autoincrement'] || $field['unique']:
948 2
                case $type == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL():
949 2
                case $type == 'Date' && $field['default'] == $this->getCurrentDateSQL():
950 1
                case $type == 'Time' && $field['default'] == $this->getCurrentTimeSQL():
951 1
                    return false;
952
            }
953
954 1
            $field['name'] = $column->getQuotedName($this);
955 1
            if (strtolower($field['type']) == 'string' && $field['length'] === null) {
956 1
                $field['length'] = 255;
957
            }
958
959 1
            $sql[] = 'ALTER TABLE '.$table->getQuotedName($this).' ADD COLUMN '.$this->getColumnDeclarationSQL($field['name'], $field);
960
        }
961
962 7
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
963 7
            if ($diff->newName !== false) {
964 1
                $newTable = new Identifier($diff->newName);
965 1
                $sql[] = 'ALTER TABLE '.$table->getQuotedName($this).' RENAME TO '.$newTable->getQuotedName($this);
966
            }
967
        }
968
969 7
        return array_merge($sql, $tableSql, $columnSql);
970
    }
971
972
    /**
973
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
974
     *
975
     * @return array
976
     */
977 25
    private function getColumnNamesInAlteredTable(TableDiff $diff)
978
    {
979 25
        $columns = array();
980
981 25
        foreach ($diff->fromTable->getColumns() as $columnName => $column) {
982 24
            $columns[strtolower($columnName)] = $column->getName();
983
        }
984
985 25
        foreach ($diff->removedColumns as $columnName => $column) {
986 5
            $columnName = strtolower($columnName);
987 5
            if (isset($columns[$columnName])) {
988 5
                unset($columns[$columnName]);
989
            }
990
        }
991
992 25 View Code Duplication
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
993 5
            $columnName = $column->getName();
994 5
            $columns[strtolower($oldColumnName)] = $columnName;
995 5
            $columns[strtolower($columnName)] = $columnName;
996
        }
997
998 25 View Code Duplication
        foreach ($diff->changedColumns as $oldColumnName => $columnDiff) {
999 18
            $columnName = $columnDiff->column->getName();
1000 18
            $columns[strtolower($oldColumnName)] = $columnName;
1001 18
            $columns[strtolower($columnName)] = $columnName;
1002
        }
1003
1004 25
        foreach ($diff->addedColumns as $columnName => $column) {
1005 4
            $columns[strtolower($columnName)] = $columnName;
1006
        }
1007
1008 25
        return $columns;
1009
    }
1010
1011
    /**
1012
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1013
     *
1014
     * @return \Doctrine\DBAL\Schema\Index[]
1015
     */
1016 25
    private function getIndexesInAlteredTable(TableDiff $diff)
1017
    {
1018 25
        $indexes = $diff->fromTable->getIndexes();
1019 25
        $columnNames = $this->getColumnNamesInAlteredTable($diff);
1020
1021 25
        foreach ($indexes as $key => $index) {
1022 9
            foreach ($diff->renamedIndexes as $oldIndexName => $renamedIndex) {
1023 4
                if (strtolower($key) === strtolower($oldIndexName)) {
1024 2
                    unset($indexes[$key]);
1025
                }
1026
            }
1027
1028 9
            $changed = false;
1029 9
            $indexColumns = array();
1030 9 View Code Duplication
            foreach ($index->getColumns() as $columnName) {
1031 9
                $normalizedColumnName = strtolower($columnName);
1032 9
                if ( ! isset($columnNames[$normalizedColumnName])) {
1033 1
                    unset($indexes[$key]);
1034 1
                    continue 2;
1035
                } else {
1036 9
                    $indexColumns[] = $columnNames[$normalizedColumnName];
1037 9
                    if ($columnName !== $columnNames[$normalizedColumnName]) {
1038 1
                        $changed = true;
1039
                    }
1040
                }
1041
            }
1042
1043 9
            if ($changed) {
1044 1
                $indexes[$key] = new Index($index->getName(), $indexColumns, $index->isUnique(), $index->isPrimary(), $index->getFlags());
1045
            }
1046
        }
1047
1048 25
        foreach ($diff->removedIndexes as $index) {
1049 2
            $indexName = strtolower($index->getName());
1050 2
            if (strlen($indexName) && isset($indexes[$indexName])) {
1051 2
                unset($indexes[$indexName]);
1052
            }
1053
        }
1054
1055 25
        foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) {
1056 4
            $indexName = strtolower($index->getName());
1057 4
            if (strlen($indexName)) {
1058 4
                $indexes[$indexName] = $index;
1059
            } else {
1060
                $indexes[] = $index;
1061
            }
1062
        }
1063
1064 25
        return $indexes;
1065
    }
1066
1067
    /**
1068
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1069
     *
1070
     * @return array
1071
     */
1072 25
    private function getForeignKeysInAlteredTable(TableDiff $diff)
1073
    {
1074 25
        $foreignKeys = $diff->fromTable->getForeignKeys();
1075 25
        $columnNames = $this->getColumnNamesInAlteredTable($diff);
1076
1077 25
        foreach ($foreignKeys as $key => $constraint) {
1078 3
            $changed = false;
1079 3
            $localColumns = array();
1080 3 View Code Duplication
            foreach ($constraint->getLocalColumns() as $columnName) {
1081 3
                $normalizedColumnName = strtolower($columnName);
1082 3
                if ( ! isset($columnNames[$normalizedColumnName])) {
1083 1
                    unset($foreignKeys[$key]);
1084 1
                    continue 2;
1085
                } else {
1086 3
                    $localColumns[] = $columnNames[$normalizedColumnName];
1087 3
                    if ($columnName !== $columnNames[$normalizedColumnName]) {
1088 1
                        $changed = true;
1089
                    }
1090
                }
1091
            }
1092
1093 3
            if ($changed) {
1094 1
                $foreignKeys[$key] = new ForeignKeyConstraint($localColumns, $constraint->getForeignTableName(), $constraint->getForeignColumns(), $constraint->getName(), $constraint->getOptions());
1095
            }
1096
        }
1097
1098 25
        foreach ($diff->removedForeignKeys as $constraint) {
1099 1
            $constraintName = strtolower($constraint->getName());
1100 1
            if (strlen($constraintName) && isset($foreignKeys[$constraintName])) {
1101 1
                unset($foreignKeys[$constraintName]);
1102
            }
1103
        }
1104
1105 25
        foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) {
1106 2
            $constraintName = strtolower($constraint->getName());
1107 2
            if (strlen($constraintName)) {
1108 1
                $foreignKeys[$constraintName] = $constraint;
1109
            } else {
1110 1
                $foreignKeys[] = $constraint;
1111
            }
1112
        }
1113
1114 25
        return $foreignKeys;
1115
    }
1116
1117
    /**
1118
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1119
     *
1120
     * @return array
1121
     */
1122 25
    private function getPrimaryIndexInAlteredTable(TableDiff $diff)
1123
    {
1124 25
        $primaryIndex = array();
1125
1126 25
        foreach ($this->getIndexesInAlteredTable($diff) as $index) {
1127 9
            if ($index->isPrimary()) {
1128 7
                $primaryIndex = array($index->getName() => $index);
1129
            }
1130
        }
1131
1132 25
        return $primaryIndex;
1133
    }
1134
}
1135