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