Completed
Pull Request — master (#3610)
by Sergei
03:03
created

DB2Platform::getCurrentDateSQL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Platforms;
6
7
use Doctrine\DBAL\Platforms\Exception\NotSupported;
8
use Doctrine\DBAL\Schema\ColumnDiff;
9
use Doctrine\DBAL\Schema\Identifier;
10
use Doctrine\DBAL\Schema\Index;
11
use Doctrine\DBAL\Schema\TableDiff;
12
use Doctrine\DBAL\Types\Type;
13
use Doctrine\DBAL\Types\Types;
14
use function array_merge;
15
use function count;
16
use function current;
17
use function explode;
18
use function implode;
19
use function sprintf;
20
use function strpos;
21
use function strtoupper;
22
23
class DB2Platform extends AbstractPlatform
24
{
25
    /**
26
     * {@inheritDoc}
27
     */
28 2063
    public function getBlobTypeDeclarationSQL(array $field) : string
29
    {
30 2063
        // todo blob(n) with $field['length'];
31
        return 'BLOB(1M)';
32
    }
33
34
    /**
35
     * {@inheritDoc}
36 1761
     */
37
    public function initializeDoctrineTypeMappings() : void
38 1761
    {
39
        $this->doctrineTypeMapping = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('bigint' => 'bigin... 'varchar' => 'string') of type array<string,string,{"bi...g","varchar":"string"}> is incompatible with the declared type array<integer,string>|null of property $doctrineTypeMapping.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
40
            'bigint'    => 'bigint',
41
            'binary'    => 'binary',
42
            'blob'      => 'blob',
43
            'character' => 'string',
44 1729
            'clob'      => 'text',
45
            'date'      => 'date',
46 1729
            'decimal'   => 'decimal',
47
            'double'    => 'float',
48
            'integer'   => 'integer',
49
            'real'      => 'float',
50
            'smallint'  => 'smallint',
51
            'time'      => 'time',
52 2184
            'timestamp' => 'datetime',
53
            'varbinary' => 'binary',
54
            'varchar'   => 'string',
55 2184
        ];
56 2017
    }
57
58
    /**
59 2184
     * {@inheritdoc}
60
     */
61
    public function isCommentedDoctrineType(Type $doctrineType) : bool
62
    {
63
        if ($doctrineType->getName() === Types::BOOLEAN) {
64
            // We require a commented boolean type in order to distinguish between boolean and smallint
65 2098
            // as both (have to) map to the same native type.
66
            return true;
67
        }
68 2098
69
        return parent::isCommentedDoctrineType($doctrineType);
70
    }
71
72
    /**
73
     * {@inheritDoc}
74 2024
     */
75
    protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string
76 2024
    {
77
        return $this->getCharTypeDeclarationSQLSnippet($length) . ' FOR BIT DATA';
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83
    protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string
84
    {
85
        return $this->getVarcharTypeDeclarationSQLSnippet($length) . ' FOR BIT DATA';
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91
    public function getClobTypeDeclarationSQL(array $field) : string
92
    {
93 2024
        // todo clob(n) with $field['length'];
94
        return 'CLOB(1M)';
95
    }
96
97
    /**
98 2250
     * {@inheritDoc}
99
     */
100 2250
    public function getName() : string
101
    {
102
        return 'db2';
103 1295
    }
104
105
    /**
106 2248
     * {@inheritDoc}
107
     */
108
    public function getBooleanTypeDeclarationSQL(array $columnDef) : string
109
    {
110
        return 'SMALLINT';
111
    }
112 2186
113
    /**
114 2186
     * {@inheritDoc}
115 2186
     */
116
    public function getIntegerTypeDeclarationSQL(array $columnDef) : string
117
    {
118
        return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
119
    }
120
121 1757
    /**
122
     * {@inheritDoc}
123 1757
     */
124
    public function getBigIntTypeDeclarationSQL(array $columnDef) : string
125
    {
126
        return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
127
    }
128
129 2100
    /**
130
     * {@inheritDoc}
131
     */
132 2100
    public function getSmallIntTypeDeclarationSQL(array $columnDef) : string
133
    {
134
        return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
135
    }
136
137
    /**
138 2190
     * {@inheritDoc}
139
     */
140 2190
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string
141
    {
142
        $autoinc = '';
143
        if (! empty($columnDef['autoincrement'])) {
144
            $autoinc = ' GENERATED BY DEFAULT AS IDENTITY';
145
        }
146 2041
147
        return $autoinc;
148 2041
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function getBitAndComparisonExpression(string $value1, string $value2) : string
154 2190
    {
155
        return 'BITAND(' . $value1 . ', ' . $value2 . ')';
156 2190
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function getBitOrComparisonExpression(string $value1, string $value2) : string
162 1964
    {
163
        return 'BITOR(' . $value1 . ', ' . $value2 . ')';
164 1964
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string
170 2017
    {
171
        switch ($unit) {
172 2017
            case DateIntervalUnit::WEEK:
173
                $interval = $this->multiplyInterval($interval, 7);
174
                $unit     = DateIntervalUnit::DAY;
175
                break;
176
177
            case DateIntervalUnit::QUARTER:
178 2190
                $interval = $this->multiplyInterval($interval, 3);
179
                $unit     = DateIntervalUnit::MONTH;
180 2190
                break;
181 2190
        }
182 2079
183
        return $date . ' ' . $operator . ' ' . $interval . ' ' . $unit;
184
    }
185 2190
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function getDateDiffExpression(string $date1, string $date2) : string
190
    {
191 1121
        return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')';
192
    }
193 1121
194
    /**
195
     * {@inheritDoc}
196
     */
197
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string
198
    {
199 233
        if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) {
200
            return 'TIMESTAMP(0) WITH DEFAULT';
201 233
        }
202
203
        return 'TIMESTAMP(0)';
204
    }
205
206
    /**
207 1987
     * {@inheritDoc}
208
     */
209
    public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string
210 1987
    {
211 1987
        return 'DATE';
212 1987
    }
213 1987
214
    /**
215 1987
     * {@inheritDoc}
216 1987
     */
217 1987
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string
218 1987
    {
219
        return 'TIME';
220
    }
221 1987
222
    /**
223
     * {@inheritdoc}
224
     */
225
    public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string
226
    {
227 1967
        $tableIdentifier = new Identifier($tableName);
228
229 1967
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this) . ' IMMEDIATE';
230
    }
231
232
    /**
233
     * This code fragment is originally from the Zend_Db_Adapter_Db2 class, but has been edited.
234
     */
235 2084
    public function getListTableColumnsSQL(string $table, ?string $database = null) : string
236
    {
237 2084
        $table = $this->quoteStringLiteral($table);
238 1927
239
        // We do the funky subquery and join syscat.columns.default this crazy way because
240
        // as of db2 v10, the column is CLOB(64k) and the distinct operator won't allow a CLOB,
241 2084
        // it wants shorter stuff like a varchar.
242
        return "
243
        SELECT
244
          cols.default,
245
          subq.*
246
        FROM (
247 2061
               SELECT DISTINCT
248
                 c.tabschema,
249 2061
                 c.tabname,
250
                 c.colname,
251
                 c.colno,
252
                 c.typename,
253
                 c.nulls,
254
                 c.length,
255 2060
                 c.scale,
256
                 c.identity,
257 2060
                 tc.type AS tabconsttype,
258
                 c.remarks AS comment,
259
                 k.colseq,
260
                 CASE
261
                 WHEN c.generated = 'D' THEN 1
262
                 ELSE 0
263 2031
                 END     AS autoincrement
264
               FROM syscat.columns c
265 2031
                 LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc
266
                     ON (k.tabschema = tc.tabschema
267 2031
                         AND k.tabname = tc.tabname
268
                         AND tc.type = 'P'))
269
                   ON (c.tabschema = k.tabschema
270
                       AND c.tabname = k.tabname
271
                       AND c.colname = k.colname)
272
               WHERE UPPER(c.tabname) = UPPER(" . $table . ')
273
               ORDER BY c.colno
274
             ) subq
275
          JOIN syscat.columns cols
276
            ON subq.tabschema = cols.tabschema
277
               AND subq.tabname = cols.tabname
278 1512
               AND subq.colno = cols.colno
279
        ORDER BY subq.colno
280 1512
        ';
281
    }
282
283
    /**
284
     * {@inheritDoc}
285
     */
286
    public function getListTablesSQL() : string
287
    {
288
        return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'";
289
    }
290
291
    /**
292
     * {@inheritDoc}
293
     */
294
    public function getListViewsSQL(string $database) : string
295
    {
296
        return 'SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS';
297
    }
298
299
    /**
300
     * {@inheritDoc}
301
     */
302
    public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string
303
    {
304
        $table = $this->quoteStringLiteral($table);
305
306
        return "SELECT   idx.INDNAME AS key_name,
307
                         idxcol.COLNAME AS column_name,
308
                         CASE
309
                             WHEN idx.UNIQUERULE = 'P' THEN 1
310
                             ELSE 0
311
                         END AS primary,
312
                         CASE
313
                             WHEN idx.UNIQUERULE = 'D' THEN 1
314
                             ELSE 0
315 1512
                         END AS non_unique
316
                FROM     SYSCAT.INDEXES AS idx
317
                JOIN     SYSCAT.INDEXCOLUSE AS idxcol
318
                ON       idx.INDSCHEMA = idxcol.INDSCHEMA AND idx.INDNAME = idxcol.INDNAME
319
                WHERE    idx.TABNAME = UPPER(" . $table . ')
320
                ORDER BY idxcol.COLSEQ ASC';
321
    }
322
323
    /**
324
     * {@inheritDoc}
325
     */
326
    public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string
327
    {
328
        $table = $this->quoteStringLiteral($table);
329 246
330
        return "SELECT   fkcol.COLNAME AS local_column,
331 246
                         fk.REFTABNAME AS foreign_table,
332
                         pkcol.COLNAME AS foreign_column,
333
                         fk.CONSTNAME AS index_name,
334
                         CASE
335
                             WHEN fk.UPDATERULE = 'R' THEN 'RESTRICT'
336
                             ELSE NULL
337 175
                         END AS on_update,
338
                         CASE
339 175
                             WHEN fk.DELETERULE = 'C' THEN 'CASCADE'
340
                             WHEN fk.DELETERULE = 'N' THEN 'SET NULL'
341
                             WHEN fk.DELETERULE = 'R' THEN 'RESTRICT'
342
                             ELSE NULL
343
                         END AS on_delete
344
                FROM     SYSCAT.REFERENCES AS fk
345 192
                JOIN     SYSCAT.KEYCOLUSE AS fkcol
346
                ON       fk.CONSTNAME = fkcol.CONSTNAME
347 192
                AND      fk.TABSCHEMA = fkcol.TABSCHEMA
348
                AND      fk.TABNAME = fkcol.TABNAME
349
                JOIN     SYSCAT.KEYCOLUSE AS pkcol
350
                ON       fk.REFKEYNAME = pkcol.CONSTNAME
351
                AND      fk.REFTABSCHEMA = pkcol.TABSCHEMA
352
                AND      fk.REFTABNAME = pkcol.TABNAME
353
                WHERE    fk.TABNAME = UPPER(" . $table . ')
354
                ORDER BY fkcol.COLSEQ ASC';
355
    }
356
357
    /**
358
     * {@inheritDoc}
359
     */
360
    public function getCreateViewSQL(string $name, string $sql) : string
361
    {
362 192
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
363
    }
364
365
    /**
366
     * {@inheritDoc}
367
     */
368
    public function getDropViewSQL(string $name) : string
369 1488
    {
370
        return 'DROP VIEW ' . $name;
371 1488
    }
372
373
    /**
374
     * {@inheritDoc}
375
     */
376
    public function getCreateDatabaseSQL(string $database) : string
377
    {
378
        return 'CREATE DATABASE ' . $database;
379
    }
380
381
    /**
382
     * {@inheritDoc}
383
     */
384
    public function getDropDatabaseSQL(string $database) : string
385
    {
386
        return 'DROP DATABASE ' . $database;
387
    }
388
389
    /**
390
     * {@inheritDoc}
391
     */
392
    public function supportsCreateDropDatabase() : bool
393
    {
394
        return false;
395
    }
396 1488
397
    /**
398
     * {@inheritDoc}
399
     */
400
    public function supportsReleaseSavepoints() : bool
401
    {
402
        return false;
403 1977
    }
404
405 1977
    /**
406
     * {@inheritdoc}
407
     */
408
    public function supportsCommentOnStatement() : bool
409
    {
410
        return true;
411 1977
    }
412
413 1977
    /**
414
     * {@inheritDoc}
415
     */
416
    public function getCurrentDateSQL() : string
417
    {
418
        return 'CURRENT DATE';
419 1877
    }
420
421 1877
    /**
422
     * {@inheritDoc}
423
     */
424
    public function getCurrentTimeSQL() : string
425
    {
426
        return 'CURRENT TIME';
427 1877
    }
428
429 1877
    /**
430
     * {@inheritDoc}
431
     */
432
    public function getCurrentTimestampSQL() : string
433
    {
434
        return 'CURRENT TIMESTAMP';
435 248
    }
436
437 248
    /**
438
     * {@inheritDoc}
439
     */
440
    public function getIndexDeclarationSQL(string $name, Index $index) : string
441
    {
442
        // Index declaration in statements like CREATE TABLE is not supported.
443 2
        throw NotSupported::new(__METHOD__);
444
    }
445 2
446
    /**
447
     * {@inheritDoc}
448
     */
449
    protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array
450
    {
451 2192
        $indexes = [];
452
        if (isset($options['indexes'])) {
453 2192
            $indexes = $options['indexes'];
454
        }
455
        $options['indexes'] = [];
456
457
        $sqls = parent::_getCreateTableSQL($tableName, $columns, $options);
458
459 1967
        foreach ($indexes as $definition) {
460
            $sqls[] = $this->getCreateIndexSQL($definition, $tableName);
461 1967
        }
462
463
        return $sqls;
464
    }
465
466
    /**
467 1964
     * {@inheritDoc}
468
     */
469 1964
    public function getAlterTableSQL(TableDiff $diff) : array
470
    {
471
        $sql         = [];
472
        $columnSql   = [];
473
        $commentsSQL = [];
474
475 1965
        $queryParts = [];
476
        foreach ($diff->addedColumns as $column) {
477 1965
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
478
                continue;
479
            }
480
481
            $columnDef = $column->toArray();
482
            $queryPart = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef);
483 477
484
            // Adding non-nullable columns to a table requires a default value to be specified.
485
            if (! empty($columnDef['notnull']) &&
486 477
                ! isset($columnDef['default']) &&
487
                empty($columnDef['autoincrement'])
488
            ) {
489
                $queryPart .= ' WITH DEFAULT';
490
            }
491
492 2190
            $queryParts[] = $queryPart;
493
494 2190
            $comment = $this->getColumnComment($column);
495 2190
496 2190
            if ($comment === null || $comment === '') {
497
                continue;
498 2190
            }
499
500 2190
            $commentsSQL[] = $this->getCommentOnColumnSQL(
501
                $diff->getName($this)->getQuotedName($this),
502 2190
                $column->getQuotedName($this),
503 2111
                $comment
504
            );
505
        }
506 2190
507
        foreach ($diff->removedColumns as $column) {
508
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
509
                continue;
510
            }
511
512 1808
            $queryParts[] =  'DROP COLUMN ' . $column->getQuotedName($this);
513
        }
514 1808
515 1808
        foreach ($diff->changedColumns as $columnDiff) {
516 1808
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
517
                continue;
518 1808
            }
519 1808
520 1048
            if ($columnDiff->hasChanged('comment')) {
521
                $commentsSQL[] = $this->getCommentOnColumnSQL(
522
                    $diff->getName($this)->getQuotedName($this),
523
                    $columnDiff->column->getQuotedName($this),
524 1048
                    $this->getColumnComment($columnDiff->column)
525 1048
                );
526
527
                if (count($columnDiff->changedProperties) === 1) {
528 1048
                    continue;
529 1048
                }
530 1048
            }
531
532 998
            $this->gatherAlterColumnSQL($diff->getName($this), $columnDiff, $sql, $queryParts);
533
        }
534
535 1048
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
536
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
537 1048
                continue;
538
            }
539 1048
540 1046
            $oldColumnName = new Identifier($oldColumnName);
541
542
            $queryParts[] =  'RENAME COLUMN ' . $oldColumnName->getQuotedName($this) .
543 802
                ' TO ' . $column->getQuotedName($this);
544 802
        }
545 802
546 2
        $tableSql = [];
547
548
        if (! $this->onSchemaAlterTable($diff, $tableSql)) {
549
            if (count($queryParts) > 0) {
550 1808
                $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(' ', $queryParts);
551 1046
            }
552
553
            // Some table alteration operations require a table reorganization.
554
            if (! empty($diff->removedColumns) || ! empty($diff->changedColumns)) {
555 1046
                $sql[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE " . $diff->getName($this)->getQuotedName($this) . "')";
556
            }
557
558 1808
            $sql = array_merge($sql, $commentsSQL);
559 1788
560
            $newName = $diff->getNewName();
561
562
            if ($newName !== null) {
563 1788
                $sql[] = sprintf(
564 940
                    'RENAME TABLE %s TO %s',
565 940
                    $diff->getName($this)->getQuotedName($this),
566 940
                    $newName->getQuotedName($this)
567 940
                );
568
            }
569
570 940
            $sql = array_merge(
571 940
                $this->getPreAlterTableIndexForeignKeySQL($diff),
572
                $sql,
573
                $this->getPostAlterTableIndexForeignKeySQL($diff)
574
            );
575 1783
        }
576
577
        return array_merge($sql, $tableSql, $columnSql);
578 1808
    }
579 996
580
    /**
581
     * Gathers the table alteration SQL for a given column diff.
582
     *
583 996
     * @param Identifier $table      The table to gather the SQL for.
584
     * @param ColumnDiff $columnDiff The column diff to evaluate.
585 996
     * @param string[]   $sql        The sequence of table alteration statements to fill.
586 996
     * @param mixed[]    $queryParts The sequence of column alteration clauses to fill.
587
     */
588
    private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts) : void
589 1808
    {
590
        $alterColumnClauses = $this->getAlterColumnClausesSQL($columnDiff);
591 1808
592 1808
        if (empty($alterColumnClauses)) {
593 1796
            return;
594
        }
595
596
        // If we have a single column alteration, we can append the clause to the main query.
597 1808
        if (count($alterColumnClauses) === 1) {
598 1794
            $queryParts[] = current($alterColumnClauses);
599
600
            return;
601 1808
        }
602
603 1808
        // We have multiple alterations for the same column,
604
        // so we need to trigger a complete ALTER TABLE statement
605 1808
        // for each ALTER COLUMN clause.
606 904
        foreach ($alterColumnClauses as $alterColumnClause) {
607 4
            $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ' . $alterColumnClause;
608 904
        }
609 904
    }
610
611
    /**
612
     * Returns the ALTER COLUMN SQL clauses for altering a column described by the given column diff.
613 1808
     *
614 1808
     * @param ColumnDiff $columnDiff The column diff to evaluate.
615 1808
     *
616 1808
     * @return string[]
617
     */
618
    private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) : array
619
    {
620 1808
        $column = $columnDiff->column->toArray();
621
622
        $alterClause = 'ALTER COLUMN ' . $columnDiff->column->getQuotedName($this);
623
624
        if ($column['columnDefinition']) {
625
            return [$alterClause . ' ' . $column['columnDefinition']];
626
        }
627
628
        $clauses = [];
629
630
        if ($columnDiff->hasChanged('type') ||
631 1783
            $columnDiff->hasChanged('length') ||
632
            $columnDiff->hasChanged('precision') ||
633 1783
            $columnDiff->hasChanged('scale') ||
634
            $columnDiff->hasChanged('fixed')
635 1783
        ) {
636 1429
            $clauses[] = $alterClause . ' SET DATA TYPE ' . $column['type']->getSQLDeclaration($column, $this);
637
        }
638
639
        if ($columnDiff->hasChanged('notnull')) {
640 1779
            $clauses[] = $column['notnull'] ? $alterClause . ' SET NOT NULL' : $alterClause . ' DROP NOT NULL';
641 1777
        }
642
643 1777
        if ($columnDiff->hasChanged('default')) {
644
            if (isset($column['default'])) {
645
                $defaultClause = $this->getDefaultValueDeclarationSQL($column);
646
647
                if ($defaultClause) {
648
                    $clauses[] = $alterClause . ' SET' . $defaultClause;
649 902
                }
650 902
            } else {
651
                $clauses[] = $alterClause . ' DROP DEFAULT';
652 902
            }
653
        }
654
655
        return $clauses;
656
    }
657
658
    /**
659
     * {@inheritDoc}
660
     */
661 1783
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) : array
662
    {
663 1783
        $sql   = [];
664
        $table = $diff->getName($this)->getQuotedName($this);
665 1783
666
        foreach ($diff->removedIndexes as $remKey => $remIndex) {
667 1783
            foreach ($diff->addedIndexes as $addKey => $addIndex) {
668 1652
                if ($remIndex->getColumns() === $addIndex->getColumns()) {
669
                    if ($remIndex->isPrimary()) {
670
                        $sql[] = 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY';
671 1757
                    } elseif ($remIndex->isUnique()) {
672
                        $sql[] = 'ALTER TABLE ' . $table . ' DROP UNIQUE ' . $remIndex->getQuotedName($this);
673 1757
                    } else {
674 1751
                        $sql[] = $this->getDropIndexSQL($remIndex, $table);
675 1749
                    }
676 1747
677 1757
                    $sql[] = $this->getCreateIndexSQL($addIndex, $table);
678
679 1743
                    unset($diff->removedIndexes[$remKey], $diff->addedIndexes[$addKey]);
680
681
                    break;
682 1757
                }
683 1508
            }
684
        }
685
686 1757
        $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff));
687 1564
688 1562
        return $sql;
689
    }
690 1562
691 1562
    /**
692
     * {@inheritdoc}
693
     */
694 1510
    protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array
695
    {
696
        if (strpos($tableName, '.') !== false) {
697
            [$schema]     = explode('.', $tableName);
0 ignored issues
show
Bug introduced by
The variable $schema does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
698 1757
            $oldIndexName = $schema . '.' . $oldIndexName;
699
        }
700
701
        return ['RENAME INDEX ' . $oldIndexName . ' TO ' . $index->getQuotedName($this)];
702
    }
703
704 1808
    /**
705
     * {@inheritDoc}
706 1808
     */
707 1808
    public function getDefaultValueDeclarationSQL(array $field) : string
708
    {
709 1808
        if (! empty($field['autoincrement'])) {
710 176
            return '';
711
        }
712
713
        if (isset($field['version']) && $field['version']) {
714
            if ((string) $field['type'] !== 'DateTime') {
715
                $field['default'] = '1';
716
            }
717
        }
718
719
        return parent::getDefaultValueDeclarationSQL($field);
720
    }
721
722
    /**
723
     * {@inheritDoc}
724
     */
725
    public function getEmptyIdentityInsertSQL(string $tableName, string $identifierColumnName) : string
726
    {
727
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)';
728
    }
729 1808
730
    /**
731 1808
     * {@inheritDoc}
732
     */
733
    public function getCreateTemporaryTableSnippetSQL() : string
734
    {
735
        return 'DECLARE GLOBAL TEMPORARY TABLE';
736
    }
737 522
738
    /**
739 522
     * {@inheritDoc}
740 279
     */
741 279
    public function getTemporaryTableName(string $tableName) : string
742
    {
743
        return 'SESSION.' . $tableName;
744 522
    }
745
746
    /**
747
     * {@inheritDoc}
748
     */
749
    protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string
750 2210
    {
751
        $where = [];
752 2210
753 1599
        if ($offset > 0) {
754
            $where[] = sprintf('db22.DC_ROWNUM >= %d', $offset + 1);
755
        }
756 2208
757
        if ($limit !== null) {
758
            $where[] = sprintf('db22.DC_ROWNUM <= %d', $offset + $limit);
759
        }
760
761
        if (empty($where)) {
762 2208
            return $query;
763
        }
764
765
        // Todo OVER() needs ORDER BY data!
766
        return sprintf(
767
            'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (%s) db21) db22 WHERE %s',
768 84
            $query,
769
            implode(' AND ', $where)
770 84
        );
771
    }
772
773
    /**
774
     * {@inheritDoc}
775
     */
776 1918
    public function getLocateExpression(string $string, string $substring, ?string $start = null) : string
777
    {
778 1918
        if ($start === null) {
779
            return sprintf('LOCATE(%s, %s)', $substring, $string);
780
        }
781
782
        return sprintf('LOCATE(%s, %s, %s)', $substring, $string, $start);
783
    }
784 116
785
    /**
786 116
     * {@inheritDoc}
787
     */
788
    public function getSubstringExpression(string $string, string $start, ?string $length = null) : string
789
    {
790
        if ($length === null) {
791
            return sprintf('SUBSTR(%s, %s)', $string, $start);
792 1959
        }
793
794 1959
        return sprintf('SUBSTR(%s, %s, %s)', $string, $start, $length);
795
    }
796 1959
797 1957
    /**
798
     * {@inheritDoc}
799
     */
800 1959
    public function getCurrentDatabaseExpression() : string
801 1957
    {
802
        return 'CURRENT_USER';
803
    }
804 1959
805 1953
    /**
806
     * {@inheritDoc}
807
     */
808
    public function supportsIdentityColumns() : bool
809 1957
    {
810 2
        return true;
811 1957
    }
812 1957
813
    /**
814
     * {@inheritDoc}
815
     */
816
    public function prefersIdentityColumns() : bool
817
    {
818
        return true;
819 1986
    }
820
821 1986
    /**
822 1986
     * {@inheritDoc}
823
     *
824
     * DB2 returns all column names in SQL result sets in uppercase.
825 1986
     */
826
    public function getSQLResultCasing(string $column) : string
827
    {
828
        return strtoupper($column);
829
    }
830
831 1827
    /**
832
     * {@inheritDoc}
833 1827
     */
834 1827
    public function getForUpdateSQL() : string
835
    {
836
        return ' WITH RR USE AND KEEP UPDATE LOCKS';
837 1827
    }
838
839
    /**
840
     * {@inheritDoc}
841
     */
842
    public function getDummySelectSQL(string $expression = '1') : string
843 176
    {
844
        return sprintf('SELECT %s FROM sysibm.sysdummy1', $expression);
845 176
    }
846
847
    /**
848
     * {@inheritDoc}
849
     *
850
     * DB2 supports savepoints, but they work semantically different than on other vendor platforms.
851 1794
     *
852
     * TODO: We have to investigate how to get DB2 up and running with savepoints.
853 1794
     */
854
    public function supportsSavepoints() : bool
855
    {
856
        return false;
857
    }
858
859
    /**
860
     * {@inheritDoc}
861 1752
     */
862
    protected function getReservedKeywordsClass() : string
863 1752
    {
864
        return Keywords\DB2Keywords::class;
865
    }
866
867
    public function getListTableCommentsSQL(string $table) : string
868
    {
869 1872
        return sprintf(
870
            <<<'SQL'
871 1872
SELECT REMARKS
872
  FROM SYSIBM.SYSTABLES
873
  WHERE NAME = UPPER( %s )
874
SQL
875
            ,
876
            $this->quoteStringLiteral($table)
877 237
        );
878
    }
879
}
880