SQLAnywherePlatform::getTimeFormatString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
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\LockMode;
24
use Doctrine\DBAL\Schema\Column;
25
use Doctrine\DBAL\Schema\ColumnDiff;
26
use Doctrine\DBAL\Schema\Constraint;
27
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
28
use Doctrine\DBAL\Schema\Identifier;
29
use Doctrine\DBAL\Schema\Index;
30
use Doctrine\DBAL\Schema\Table;
31
use Doctrine\DBAL\Schema\TableDiff;
32
use Doctrine\DBAL\TransactionIsolationLevel;
33
use function array_merge;
34
use function array_unique;
35
use function array_values;
36
use function count;
37
use function explode;
38
use function func_get_args;
39
use function get_class;
40
use function implode;
41
use function is_string;
42
use function preg_replace;
43
use function strlen;
44
use function strpos;
45
use function strtoupper;
46
use function substr;
47
48
/**
49
 * The SQLAnywherePlatform provides the behavior, features and SQL dialect of the
50
 * SAP Sybase SQL Anywhere 10 database platform.
51
 *
52
 * @author Steve Müller <[email protected]>
53
 * @link   www.doctrine-project.org
54
 * @since  2.5
55
 */
56
class SQLAnywherePlatform extends AbstractPlatform
57
{
58
    /**
59
     * @var int
60
     */
61
    const FOREIGN_KEY_MATCH_SIMPLE = 1;
62
    /**
63
     * @var int
64
     */
65
    const FOREIGN_KEY_MATCH_FULL = 2;
66
    /**
67
     * @var int
68
     */
69
    const FOREIGN_KEY_MATCH_SIMPLE_UNIQUE = 129;
70
    /**
71
     * @var int
72
     */
73
    const FOREIGN_KEY_MATCH_FULL_UNIQUE = 130;
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function appendLockHint($fromClause, $lockMode)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
79
    {
80
        switch (true) {
81
            case $lockMode === LockMode::NONE:
82
                return $fromClause . ' WITH (NOLOCK)';
83
84
            case $lockMode === LockMode::PESSIMISTIC_READ:
85
                return $fromClause . ' WITH (UPDLOCK)';
86
87
            case $lockMode === LockMode::PESSIMISTIC_WRITE:
88
                return $fromClause . ' WITH (XLOCK)';
89
90
            default:
91
                return $fromClause;
92
        }
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     *
98
     * SQL Anywhere supports a maximum length of 128 bytes for identifiers.
99
     */
100
    public function fixSchemaElementName($schemaElementName)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
101
    {
102
        $maxIdentifierLength = $this->getMaxIdentifierLength();
103
104
        if (strlen($schemaElementName) > $maxIdentifierLength) {
105
            return substr($schemaElementName, 0, $maxIdentifierLength);
106
        }
107
108
        return $schemaElementName;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
115
    {
116
        $query = '';
117
118
        if ($foreignKey->hasOption('match')) {
119
            $query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match'));
120
        }
121
122
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
123
124
        if ($foreignKey->hasOption('check_on_commit') && (boolean) $foreignKey->getOption('check_on_commit')) {
125
            $query .= ' CHECK ON COMMIT';
126
        }
127
128
        if ($foreignKey->hasOption('clustered') && (boolean) $foreignKey->getOption('clustered')) {
129
            $query .= ' CLUSTERED';
130
        }
131
132
        if ($foreignKey->hasOption('for_olap_workload') && (boolean) $foreignKey->getOption('for_olap_workload')) {
133
            $query .= ' FOR OLAP WORKLOAD';
134
        }
135
136
        return $query;
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function getAlterTableSQL(TableDiff $diff)
143
    {
144
        $sql          = [];
145
        $columnSql    = [];
146
        $commentsSQL  = [];
147
        $tableSql     = [];
148
        $alterClauses = [];
149
150
        /** @var \Doctrine\DBAL\Schema\Column $column */
151
        foreach ($diff->addedColumns as $column) {
152
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
153
                continue;
154
            }
155
156
            $alterClauses[] = $this->getAlterTableAddColumnClause($column);
157
158
            $comment = $this->getColumnComment($column);
159
160 View Code Duplication
            if (null !== $comment && '' !== $comment) {
161
                $commentsSQL[] = $this->getCommentOnColumnSQL(
162
                    $diff->getName($this)->getQuotedName($this),
163
                    $column->getQuotedName($this),
164
                    $comment
165
                );
166
            }
167
        }
168
169
        /** @var \Doctrine\DBAL\Schema\Column $column */
170
        foreach ($diff->removedColumns as $column) {
171
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
172
                continue;
173
            }
174
175
            $alterClauses[] = $this->getAlterTableRemoveColumnClause($column);
176
        }
177
178
        /** @var \Doctrine\DBAL\Schema\ColumnDiff $columnDiff */
179
        foreach ($diff->changedColumns as $columnDiff) {
180
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
181
                continue;
182
            }
183
184
            $alterClause = $this->getAlterTableChangeColumnClause($columnDiff);
185
186
            if (null !== $alterClause) {
187
                $alterClauses[] = $alterClause;
188
            }
189
190 View Code Duplication
            if ($columnDiff->hasChanged('comment')) {
191
                $column = $columnDiff->column;
192
193
                $commentsSQL[] = $this->getCommentOnColumnSQL(
194
                    $diff->getName($this)->getQuotedName($this),
195
                    $column->getQuotedName($this),
196
                    $this->getColumnComment($column)
197
                );
198
            }
199
        }
200
201 View Code Duplication
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
202
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
203
                continue;
204
            }
205
206
            $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
207
                $this->getAlterTableRenameColumnClause($oldColumnName, $column);
208
        }
209
210
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
211
            if ( ! empty($alterClauses)) {
212
                $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . implode(", ", $alterClauses);
213
            }
214
215
            $sql = array_merge($sql, $commentsSQL);
216
217
            if ($diff->newName !== false) {
218
                $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
219
                    $this->getAlterTableRenameTableClause($diff->getNewName());
220
            }
221
222
            $sql = array_merge(
223
                $this->getPreAlterTableIndexForeignKeySQL($diff),
224
                $sql,
225
                $this->getPostAlterTableIndexForeignKeySQL($diff)
226
            );
227
        }
228
229
        return array_merge($sql, $tableSql, $columnSql);
230
    }
231
232
    /**
233
     * Returns the SQL clause for creating a column in a table alteration.
234
     *
235
     * @param Column $column The column to add.
236
     *
237
     * @return string
238
     */
239
    protected function getAlterTableAddColumnClause(Column $column)
240
    {
241
        return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
242
    }
243
244
    /**
245
     * Returns the SQL clause for altering a table.
246
     *
247
     * @param Identifier $tableName The quoted name of the table to alter.
248
     *
249
     * @return string
250
     */
251
    protected function getAlterTableClause(Identifier $tableName)
252
    {
253
        return 'ALTER TABLE ' . $tableName->getQuotedName($this);
254
    }
255
256
    /**
257
     * Returns the SQL clause for dropping a column in a table alteration.
258
     *
259
     * @param Column $column The column to drop.
260
     *
261
     * @return string
262
     */
263
    protected function getAlterTableRemoveColumnClause(Column $column)
264
    {
265
        return 'DROP ' . $column->getQuotedName($this);
266
    }
267
268
    /**
269
     * Returns the SQL clause for renaming a column in a table alteration.
270
     *
271
     * @param string $oldColumnName The quoted name of the column to rename.
272
     * @param Column $column        The column to rename to.
273
     *
274
     * @return string
275
     */
276
    protected function getAlterTableRenameColumnClause($oldColumnName, Column $column)
277
    {
278
        $oldColumnName = new Identifier($oldColumnName);
279
280
        return 'RENAME ' . $oldColumnName->getQuotedName($this) .' TO ' . $column->getQuotedName($this);
281
    }
282
283
    /**
284
     * Returns the SQL clause for renaming a table in a table alteration.
285
     *
286
     * @param Identifier $newTableName The quoted name of the table to rename to.
287
     *
288
     * @return string
289
     */
290
    protected function getAlterTableRenameTableClause(Identifier $newTableName)
291
    {
292
        return 'RENAME ' . $newTableName->getQuotedName($this);
293
    }
294
295
    /**
296
     * Returns the SQL clause for altering a column in a table alteration.
297
     *
298
     * This method returns null in case that only the column comment has changed.
299
     * Changes in column comments have to be handled differently.
300
     *
301
     * @param ColumnDiff $columnDiff The diff of the column to alter.
302
     *
303
     * @return string|null
304
     */
305
    protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff)
306
    {
307
        $column = $columnDiff->column;
308
309
        // Do not return alter clause if only comment has changed.
310
        if ( ! ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1)) {
311
            $columnAlterationClause = 'ALTER ' .
312
                $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
313
314
            if ($columnDiff->hasChanged('default') && null === $column->getDefault()) {
315
                $columnAlterationClause .= ', ALTER ' . $column->getQuotedName($this) . ' DROP DEFAULT';
316
            }
317
318
            return $columnAlterationClause;
319
        }
320
321
        return null;
322
    }
323
324
    /**
325
     * {@inheritdoc}
326
     */
327
    public function getBigIntTypeDeclarationSQL(array $columnDef)
328
    {
329
        $columnDef['integer_type'] = 'BIGINT';
330
331
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
332
    }
333
334
    /**
335
     * {@inheritdoc}
336
     */
337
    public function getBinaryDefaultLength()
338
    {
339
        return 1;
340
    }
341
342
    /**
343
     * {@inheritdoc}
344
     */
345
    public function getBinaryMaxLength()
346
    {
347
        return 32767;
348
    }
349
350
    /**
351
     * {@inheritdoc}
352
     */
353
    public function getBlobTypeDeclarationSQL(array $field)
354
    {
355
        return 'LONG BINARY';
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     *
361
     * BIT type columns require an explicit NULL declaration
362
     * in SQL Anywhere if they shall be nullable.
363
     * Otherwise by just omitting the NOT NULL clause,
364
     * SQL Anywhere will declare them NOT NULL nonetheless.
365
     */
366
    public function getBooleanTypeDeclarationSQL(array $columnDef)
367
    {
368
        $nullClause = isset($columnDef['notnull']) && (boolean) $columnDef['notnull'] === false ? ' NULL' : '';
369
370
        return 'BIT' . $nullClause;
371
    }
372
373
    /**
374
     * {@inheritdoc}
375
     */
376
    public function getClobTypeDeclarationSQL(array $field)
377
    {
378
        return 'TEXT';
379
    }
380
381
    /**
382
     * {@inheritdoc}
383
     */
384 View Code Duplication
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
385
    {
386
        $tableName = new Identifier($tableName);
387
        $columnName = new Identifier($columnName);
388
        $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment);
389
390
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . '.' . $columnName->getQuotedName($this) .
391
            " IS $comment";
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    public function getConcatExpression()
398
    {
399
        return 'STRING(' . implode(', ', (array) func_get_args()) . ')';
400
    }
401
402
    /**
403
     * {@inheritdoc}
404
     */
405
    public function getCreateConstraintSQL(Constraint $constraint, $table)
406
    {
407
        if ($constraint instanceof ForeignKeyConstraint) {
408
            return $this->getCreateForeignKeySQL($constraint, $table);
409
        }
410
411
        if ($table instanceof Table) {
412
            $table = $table->getQuotedName($this);
413
        }
414
415
        return 'ALTER TABLE ' . $table .
416
               ' ADD ' . $this->getTableConstraintDeclarationSQL($constraint, $constraint->getQuotedName($this));
417
    }
418
419
    /**
420
     * {@inheritdoc}
421
     */
422
    public function getCreateDatabaseSQL($database)
423
    {
424
        $database = new Identifier($database);
425
426
        return "CREATE DATABASE '" . $database->getName() . "'";
427
    }
428
429
    /**
430
     * {@inheritdoc}
431
     *
432
     * Appends SQL Anywhere specific flags if given.
433
     */
434
    public function getCreateIndexSQL(Index $index, $table)
435
    {
436
        return parent::getCreateIndexSQL($index, $table). $this->getAdvancedIndexOptionsSQL($index);
437
    }
438
439
    /**
440
     * {@inheritdoc}
441
     */
442
    public function getCreatePrimaryKeySQL(Index $index, $table)
443
    {
444
        if ($table instanceof Table) {
445
            $table = $table->getQuotedName($this);
446
        }
447
448
        return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index);
449
    }
450
451
    /**
452
     * {@inheritdoc}
453
     */
454
    public function getCreateTemporaryTableSnippetSQL()
455
    {
456
        return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE';
457
    }
458
459
    /**
460
     * {@inheritdoc}
461
     */
462
    public function getCreateViewSQL($name, $sql)
463
    {
464
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
465
    }
466
467
    /**
468
     * {@inheritdoc}
469
     */
470
    public function getCurrentDateSQL()
471
    {
472
        return 'CURRENT DATE';
473
    }
474
475
    /**
476
     * {@inheritdoc}
477
     */
478
    public function getCurrentTimeSQL()
479
    {
480
        return 'CURRENT TIME';
481
    }
482
483
    /**
484
     * {@inheritdoc}
485
     */
486
    public function getCurrentTimestampSQL()
487
    {
488
        return 'CURRENT TIMESTAMP';
489
    }
490
491
    /**
492
     * {@inheritdoc}
493
     */
494
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
495
    {
496
        $factorClause = '';
497
498
        if ('-' === $operator) {
499
            $factorClause = '-1 * ';
500
        }
501
502
        return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')';
503
    }
504
505
    /**
506
     * {@inheritdoc}
507
     */
508
    public function getDateDiffExpression($date1, $date2)
509
    {
510
        return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')';
511
    }
512
513
    /**
514
     * {@inheritdoc}
515
     */
516
    public function getDateTimeFormatString()
517
    {
518
        return 'Y-m-d H:i:s.u';
519
    }
520
521
    /**
522
     * {@inheritdoc}
523
     */
524
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
525
    {
526
        return 'DATETIME';
527
    }
528
529
    /**
530
     * {@inheritdoc}
531
     */
532
    public function getDateTimeTzFormatString()
533
    {
534
        return $this->getDateTimeFormatString();
535
    }
536
537
    /**
538
     * {@inheritdoc}
539
     */
540
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
541
    {
542
        return 'DATE';
543
    }
544
545
    /**
546
     * {@inheritdoc}
547
     */
548
    public function getDefaultTransactionIsolationLevel()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
549
    {
550
        return TransactionIsolationLevel::READ_UNCOMMITTED;
551
    }
552
553
    /**
554
     * {@inheritdoc}
555
     */
556
    public function getDropDatabaseSQL($database)
557
    {
558
        $database = new Identifier($database);
559
560
        return "DROP DATABASE '" . $database->getName() . "'";
561
    }
562
563
    /**
564
     * {@inheritdoc}
565
     */
566
    public function getDropIndexSQL($index, $table = null)
567
    {
568
        if ($index instanceof Index) {
569
            $index = $index->getQuotedName($this);
570
        }
571
572
        if ( ! is_string($index)) {
573
            throw new \InvalidArgumentException(
574
                'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' .
575
                '\Doctrine\DBAL\Schema\Index.'
576
            );
577
        }
578
579
        if ( ! isset($table)) {
580
            return 'DROP INDEX ' . $index;
581
        }
582
583
        if ($table instanceof Table) {
584
            $table = $table->getQuotedName($this);
585
        }
586
587
        if ( ! is_string($table)) {
588
            throw new \InvalidArgumentException(
589
                'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' .
590
                '\Doctrine\DBAL\Schema\Table.'
591
            );
592
        }
593
594
        return 'DROP INDEX ' . $table . '.' . $index;
595
    }
596
597
    /**
598
     * {@inheritdoc}
599
     */
600
    public function getDropViewSQL($name)
601
    {
602
        return 'DROP VIEW ' . $name;
603
    }
604
605
    /**
606
     * {@inheritdoc}
607
     */
608
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
609
    {
610
        $sql              = '';
611
        $foreignKeyName   = $foreignKey->getName();
612
        $localColumns     = $foreignKey->getQuotedLocalColumns($this);
613
        $foreignColumns   = $foreignKey->getQuotedForeignColumns($this);
614
        $foreignTableName = $foreignKey->getQuotedForeignTableName($this);
615
616
        if ( ! empty($foreignKeyName)) {
617
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
618
        }
619
620
        if (empty($localColumns)) {
621
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
622
        }
623
624
        if (empty($foreignColumns)) {
625
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
626
        }
627
628
        if (empty($foreignTableName)) {
629
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
630
        }
631
632
        if ($foreignKey->hasOption('notnull') && (boolean) $foreignKey->getOption('notnull')) {
633
            $sql .= 'NOT NULL ';
634
        }
635
636
        return $sql .
637
            'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' .
638
            'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) .
639
            ' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')';
640
    }
641
642
    /**
643
     * Returns foreign key MATCH clause for given type.
644
     *
645
     * @param int $type The foreign key match type
646
     *
647
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
648
     *
649
     * @throws \InvalidArgumentException if unknown match type given
650
     */
651
    public function getForeignKeyMatchClauseSQL($type)
652
    {
653
        switch ((int) $type) {
654
            case self::FOREIGN_KEY_MATCH_SIMPLE:
655
                return 'SIMPLE';
656
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
657
            case self::FOREIGN_KEY_MATCH_FULL:
658
                return 'FULL';
659
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
660
            case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE:
661
                return 'UNIQUE SIMPLE';
662
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
663
            case self::FOREIGN_KEY_MATCH_FULL_UNIQUE:
664
                return 'UNIQUE FULL';
665
            default:
666
                throw new \InvalidArgumentException('Invalid foreign key match type: ' . $type);
667
        }
668
    }
669
670
    /**
671
     * {@inheritdoc}
672
     */
673
    public function getForeignKeyReferentialActionSQL($action)
674
    {
675
        // NO ACTION is not supported, therefore falling back to RESTRICT.
676
        if (strtoupper($action) === 'NO ACTION') {
677
            return 'RESTRICT';
678
        }
679
680
        return parent::getForeignKeyReferentialActionSQL($action);
681
    }
682
683
    /**
684
     * {@inheritdoc}
685
     */
686
    public function getForUpdateSQL()
687
    {
688
        return '';
689
    }
690
691
    /**
692
     * {@inheritdoc}
693
     *
694
     * @deprecated Use application-generated UUIDs instead
695
     */
696
    public function getGuidExpression()
697
    {
698
        return 'NEWID()';
699
    }
700
701
    /**
702
     * {@inheritdoc}
703
     */
704
    public function getGuidTypeDeclarationSQL(array $field)
705
    {
706
        return 'UNIQUEIDENTIFIER';
707
    }
708
709
    /**
710
     * {@inheritdoc}
711
     */
712
    public function getIndexDeclarationSQL($name, Index $index)
713
    {
714
        // Index declaration in statements like CREATE TABLE is not supported.
715
        throw DBALException::notSupported(__METHOD__);
716
    }
717
718
    /**
719
     * {@inheritdoc}
720
     */
721
    public function getIntegerTypeDeclarationSQL(array $columnDef)
722
    {
723
        $columnDef['integer_type'] = 'INT';
724
725
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
726
    }
727
728
    /**
729
     * {@inheritdoc}
730
     */
731
    public function getListDatabasesSQL()
732
    {
733
        return 'SELECT db_name(number) AS name FROM sa_db_list()';
734
    }
735
736
    /**
737
     * {@inheritdoc}
738
     */
739
    public function getListTableColumnsSQL($table, $database = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
740
    {
741
        $user = 'USER_NAME()';
742
743 View Code Duplication
        if (strpos($table, '.') !== false) {
744
            list($user, $table) = explode('.', $table);
745
            $user = $this->quoteStringLiteral($user);
746
        }
747
748
        return "SELECT    col.column_name,
749
                          COALESCE(def.user_type_name, def.domain_name) AS 'type',
750
                          def.declared_width AS 'length',
751
                          def.scale,
752
                          CHARINDEX('unsigned', def.domain_name) AS 'unsigned',
753
                          IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull',
754
                          col.\"default\",
755
                          def.is_autoincrement AS 'autoincrement',
756
                          rem.remarks AS 'comment'
757
                FROM      sa_describe_query('SELECT * FROM \"$table\"') AS def
758
                JOIN      SYS.SYSTABCOL AS col
759
                ON        col.table_id = def.base_table_id AND col.column_id = def.base_column_id
760
                LEFT JOIN SYS.SYSREMARK AS rem
761
                ON        col.object_id = rem.object_id
762
                WHERE     def.base_owner_name = $user
763
                ORDER BY  def.base_column_id ASC";
764
    }
765
766
    /**
767
     * {@inheritdoc}
768
     *
769
     * @todo Where is this used? Which information should be retrieved?
770
     */
771 View Code Duplication
    public function getListTableConstraintsSQL($table)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
772
    {
773
        $user = '';
774
775
        if (strpos($table, '.') !== false) {
776
            list($user, $table) = explode('.', $table);
777
            $user = $this->quoteStringLiteral($user);
778
            $table = $this->quoteStringLiteral($table);
779
        } else {
780
            $table = $this->quoteStringLiteral($table);
781
        }
782
783
        return "SELECT con.*
784
                FROM   SYS.SYSCONSTRAINT AS con
785
                JOIN   SYS.SYSTAB AS tab ON con.table_object_id = tab.object_id
786
                WHERE  tab.table_name = $table
787
                AND    tab.creator = USER_ID($user)";
788
    }
789
790
    /**
791
     * {@inheritdoc}
792
     */
793 View Code Duplication
    public function getListTableForeignKeysSQL($table)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
794
    {
795
        $user = '';
796
797
        if (strpos($table, '.') !== false) {
798
            list($user, $table) = explode('.', $table);
799
            $user = $this->quoteStringLiteral($user);
800
            $table = $this->quoteStringLiteral($table);
801
        } else {
802
            $table = $this->quoteStringLiteral($table);
803
        }
804
805
        return "SELECT    fcol.column_name AS local_column,
806
                          ptbl.table_name AS foreign_table,
807
                          pcol.column_name AS foreign_column,
808
                          idx.index_name,
809
                          IF fk.nulls = 'N'
810
                              THEN 1
811
                              ELSE NULL
812
                          ENDIF AS notnull,
813
                          CASE ut.referential_action
814
                              WHEN 'C' THEN 'CASCADE'
815
                              WHEN 'D' THEN 'SET DEFAULT'
816
                              WHEN 'N' THEN 'SET NULL'
817
                              WHEN 'R' THEN 'RESTRICT'
818
                              ELSE NULL
819
                          END AS  on_update,
820
                          CASE dt.referential_action
821
                              WHEN 'C' THEN 'CASCADE'
822
                              WHEN 'D' THEN 'SET DEFAULT'
823
                              WHEN 'N' THEN 'SET NULL'
824
                              WHEN 'R' THEN 'RESTRICT'
825
                              ELSE NULL
826
                          END AS on_delete,
827
                          IF fk.check_on_commit = 'Y'
828
                              THEN 1
829
                              ELSE NULL
830
                          ENDIF AS check_on_commit, -- check_on_commit flag
831
                          IF ftbl.clustered_index_id = idx.index_id
832
                              THEN 1
833
                              ELSE NULL
834
                          ENDIF AS 'clustered', -- clustered flag
835
                          IF fk.match_type = 0
836
                              THEN NULL
837
                              ELSE fk.match_type
838
                          ENDIF AS 'match', -- match option
839
                          IF pidx.max_key_distance = 1
840
                              THEN 1
841
                              ELSE NULL
842
                          ENDIF AS for_olap_workload -- for_olap_workload flag
843
                FROM      SYS.SYSFKEY AS fk
844
                JOIN      SYS.SYSIDX AS idx
845
                ON        fk.foreign_table_id = idx.table_id
846
                AND       fk.foreign_index_id = idx.index_id
847
                JOIN      SYS.SYSPHYSIDX pidx
848
                ON        idx.table_id = pidx.table_id
849
                AND       idx.phys_index_id = pidx.phys_index_id
850
                JOIN      SYS.SYSTAB AS ptbl
851
                ON        fk.primary_table_id = ptbl.table_id
852
                JOIN      SYS.SYSTAB AS ftbl
853
                ON        fk.foreign_table_id = ftbl.table_id
854
                JOIN      SYS.SYSIDXCOL AS idxcol
855
                ON        idx.table_id = idxcol.table_id
856
                AND       idx.index_id = idxcol.index_id
857
                JOIN      SYS.SYSTABCOL AS pcol
858
                ON        ptbl.table_id = pcol.table_id
859
                AND       idxcol.primary_column_id = pcol.column_id
860
                JOIN      SYS.SYSTABCOL AS fcol
861
                ON        ftbl.table_id = fcol.table_id
862
                AND       idxcol.column_id = fcol.column_id
863
                LEFT JOIN SYS.SYSTRIGGER ut
864
                ON        fk.foreign_table_id = ut.foreign_table_id
865
                AND       fk.foreign_index_id = ut.foreign_key_id
866
                AND       ut.event = 'C'
867
                LEFT JOIN SYS.SYSTRIGGER dt
868
                ON        fk.foreign_table_id = dt.foreign_table_id
869
                AND       fk.foreign_index_id = dt.foreign_key_id
870
                AND       dt.event = 'D'
871
                WHERE     ftbl.table_name = $table
872
                AND       ftbl.creator = USER_ID($user)
873
                ORDER BY  fk.foreign_index_id ASC, idxcol.sequence ASC";
874
    }
875
876
    /**
877
     * {@inheritdoc}
878
     */
879 View Code Duplication
    public function getListTableIndexesSQL($table, $currentDatabase = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
880
    {
881
        $user = '';
882
883
        if (strpos($table, '.') !== false) {
884
            list($user, $table) = explode('.', $table);
885
            $user = $this->quoteStringLiteral($user);
886
            $table = $this->quoteStringLiteral($table);
887
        } else {
888
            $table = $this->quoteStringLiteral($table);
889
        }
890
891
        return "SELECT   idx.index_name AS key_name,
892
                         IF idx.index_category = 1
893
                             THEN 1
894
                             ELSE 0
895
                         ENDIF AS 'primary',
896
                         col.column_name,
897
                         IF idx.\"unique\" IN(1, 2, 5)
898
                             THEN 0
899
                             ELSE 1
900
                         ENDIF AS non_unique,
901
                         IF tbl.clustered_index_id = idx.index_id
902
                             THEN 1
903
                             ELSE NULL
904
                         ENDIF AS 'clustered', -- clustered flag
905
                         IF idx.\"unique\" = 5
906
                             THEN 1
907
                             ELSE NULL
908
                         ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag
909
                         IF pidx.max_key_distance = 1
910
                              THEN 1
911
                              ELSE NULL
912
                          ENDIF AS for_olap_workload -- for_olap_workload flag
913
                FROM     SYS.SYSIDX AS idx
914
                JOIN     SYS.SYSPHYSIDX pidx
915
                ON       idx.table_id = pidx.table_id
916
                AND      idx.phys_index_id = pidx.phys_index_id
917
                JOIN     SYS.SYSIDXCOL AS idxcol
918
                ON       idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id
919
                JOIN     SYS.SYSTABCOL AS col
920
                ON       idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id
921
                JOIN     SYS.SYSTAB AS tbl
922
                ON       idx.table_id = tbl.table_id
923
                WHERE    tbl.table_name = $table
924
                AND      tbl.creator = USER_ID($user)
925
                AND      idx.index_category != 2 -- exclude indexes implicitly created by foreign key constraints
926
                ORDER BY idx.index_id ASC, idxcol.sequence ASC";
927
    }
928
929
    /**
930
     * {@inheritdoc}
931
     */
932
    public function getListTablesSQL()
933
    {
934
        return "SELECT   tbl.table_name
935
                FROM     SYS.SYSTAB AS tbl
936
                JOIN     SYS.SYSUSER AS usr ON tbl.creator = usr.user_id
937
                JOIN     dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id
938
                WHERE    tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP'
939
                AND      usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
940
                AND      obj.type = 'U' -- user created tables only
941
                ORDER BY tbl.table_name ASC";
942
    }
943
944
    /**
945
     * {@inheritdoc}
946
     *
947
     * @todo Where is this used? Which information should be retrieved?
948
     */
949
    public function getListUsersSQL()
950
    {
951
        return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC';
952
    }
953
954
    /**
955
     * {@inheritdoc}
956
     */
957
    public function getListViewsSQL($database)
958
    {
959
        return "SELECT   tbl.table_name, v.view_def
960
                FROM     SYS.SYSVIEW v
961
                JOIN     SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id
962
                JOIN     SYS.SYSUSER usr ON tbl.creator = usr.user_id
963
                JOIN     dbo.SYSOBJECTS obj ON tbl.object_id = obj.id
964
                WHERE    usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
965
                ORDER BY tbl.table_name ASC";
966
    }
967
968
    /**
969
     * {@inheritdoc}
970
     */
971 View Code Duplication
    public function getLocateExpression($str, $substr, $startPos = false)
972
    {
973
        if ($startPos == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
974
            return 'LOCATE(' . $str . ', ' . $substr . ')';
975
        }
976
977
        return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')';
978
    }
979
980
    /**
981
     * {@inheritdoc}
982
     */
983
    public function getMaxIdentifierLength()
984
    {
985
        return 128;
986
    }
987
988
    /**
989
     * {@inheritdoc}
990
     */
991
    public function getMd5Expression($column)
992
    {
993
        return "HASH(" . $column . ", 'MD5')";
994
    }
995
996
    /**
997
     * {@inheritdoc}
998
     */
999
    public function getName()
1000
    {
1001
        return 'sqlanywhere';
1002
    }
1003
1004
    /**
1005
     * Obtain DBMS specific SQL code portion needed to set a primary key
1006
     * declaration to be used in statements like ALTER TABLE.
1007
     *
1008
     * @param Index  $index Index definition
1009
     * @param string $name  Name of the primary key
0 ignored issues
show
Documentation introduced by
Should the type for parameter $name not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1010
     *
1011
     * @return string DBMS specific SQL code portion needed to set a primary key
1012
     *
1013
     * @throws \InvalidArgumentException if the given index is not a primary key.
1014
     */
1015
    public function getPrimaryKeyDeclarationSQL(Index $index, $name = null)
1016
    {
1017
        if ( ! $index->isPrimary()) {
1018
            throw new \InvalidArgumentException(
1019
                'Can only create primary key declarations with getPrimaryKeyDeclarationSQL()'
1020
            );
1021
        }
1022
1023
        return $this->getTableConstraintDeclarationSQL($index, $name);
1024
    }
1025
1026
    /**
1027
     * {@inheritdoc}
1028
     */
1029
    public function getSetTransactionIsolationSQL($level)
1030
    {
1031
        return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level);
1032
    }
1033
1034
    /**
1035
     * {@inheritdoc}
1036
     */
1037
    public function getSmallIntTypeDeclarationSQL(array $columnDef)
1038
    {
1039
        $columnDef['integer_type'] = 'SMALLINT';
1040
1041
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
1042
    }
1043
1044
    /**
1045
     * Returns the SQL statement for starting an existing database.
1046
     *
1047
     * In SQL Anywhere you can start and stop databases on a
1048
     * database server instance.
1049
     * This is a required statement after having created a new database
1050
     * as it has to be explicitly started to be usable.
1051
     * SQL Anywhere does not automatically start a database after creation!
1052
     *
1053
     * @param string $database Name of the database to start.
1054
     *
1055
     * @return string
1056
     */
1057
    public function getStartDatabaseSQL($database)
1058
    {
1059
        $database = new Identifier($database);
1060
1061
        return "START DATABASE '" . $database->getName() . "' AUTOSTOP OFF";
1062
    }
1063
1064
    /**
1065
     * Returns the SQL statement for stopping a running database.
1066
     *
1067
     * In SQL Anywhere you can start and stop databases on a
1068
     * database server instance.
1069
     * This is a required statement before dropping an existing database
1070
     * as it has to be explicitly stopped before it can be dropped.
1071
     *
1072
     * @param string $database Name of the database to stop.
1073
     *
1074
     * @return string
1075
     */
1076
    public function getStopDatabaseSQL($database)
1077
    {
1078
        $database = new Identifier($database);
1079
1080
        return 'STOP DATABASE "' . $database->getName() . '" UNCONDITIONALLY';
1081
    }
1082
1083
    /**
1084
     * {@inheritdoc}
1085
     */
1086 View Code Duplication
    public function getSubstringExpression($value, $from, $length = null)
1087
    {
1088
        if (null === $length) {
1089
            return 'SUBSTRING(' . $value . ', ' . $from . ')';
1090
        }
1091
1092
        return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')';
1093
    }
1094
1095
    /**
1096
     * {@inheritdoc}
1097
     */
1098
    public function getTemporaryTableSQL()
1099
    {
1100
        return 'GLOBAL TEMPORARY';
1101
    }
1102
1103
    /**
1104
     * {@inheritdoc}
1105
     */
1106
    public function getTimeFormatString()
1107
    {
1108
        return 'H:i:s.u';
1109
    }
1110
1111
    /**
1112
     * {@inheritdoc}
1113
     */
1114
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
1115
    {
1116
        return 'TIME';
1117
    }
1118
1119
    /**
1120
     * {@inheritdoc}
1121
     */
1122
    public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false)
1123
    {
1124
        if ( ! $char) {
1125
            switch ($pos) {
1126
                case TrimMode::LEADING:
1127
                    return $this->getLtrimExpression($str);
1128
                case TrimMode::TRAILING:
1129
                    return $this->getRtrimExpression($str);
1130
                default:
1131
                    return 'TRIM(' . $str . ')';
1132
            }
1133
        }
1134
1135
        $pattern = "'%[^' + $char + ']%'";
1136
1137
        switch ($pos) {
1138 View Code Duplication
            case TrimMode::LEADING:
1139
                return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))';
1140 View Code Duplication
            case TrimMode::TRAILING:
1141
                return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))';
1142
            default:
1143
                return
1144
                    'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' .
1145
                    'PATINDEX(' . $pattern . ', REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))';
1146
        }
1147
    }
1148
1149
    /**
1150
     * {@inheritdoc}
1151
     */
1152
    public function getTruncateTableSQL($tableName, $cascade = false)
1153
    {
1154
        $tableIdentifier = new Identifier($tableName);
1155
1156
        return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this);
1157
    }
1158
1159
    /**
1160
     * {@inheritdoc}
1161
     */
1162
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
1163
    {
1164
        if ($index->isPrimary()) {
1165
            throw new \InvalidArgumentException(
1166
                'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().'
1167
            );
1168
        }
1169
1170
        if ( ! $index->isUnique()) {
1171
            throw new \InvalidArgumentException(
1172
                'Can only create unique constraint declarations, no common index declarations with ' .
1173
                'getUniqueConstraintDeclarationSQL().'
1174
            );
1175
        }
1176
1177
        return $this->getTableConstraintDeclarationSQL($index, $name);
1178
    }
1179
1180
    /**
1181
     * {@inheritdoc}
1182
     */
1183
    public function getVarcharDefaultLength()
1184
    {
1185
        return 1;
1186
    }
1187
1188
    /**
1189
     * {@inheritdoc}
1190
     */
1191
    public function getVarcharMaxLength()
1192
    {
1193
        return 32767;
1194
    }
1195
1196
    /**
1197
     * {@inheritdoc}
1198
     */
1199
    public function hasNativeGuidType()
1200
    {
1201
        return true;
1202
    }
1203
1204
    /**
1205
     * {@inheritdoc}
1206
     */
1207
    public function prefersIdentityColumns()
1208
    {
1209
        return true;
1210
    }
1211
1212
    /**
1213
     * {@inheritdoc}
1214
     */
1215
    public function supportsCommentOnStatement()
1216
    {
1217
        return true;
1218
    }
1219
1220
    /**
1221
     * {@inheritdoc}
1222
     */
1223
    public function supportsIdentityColumns()
1224
    {
1225
        return true;
1226
    }
1227
1228
    /**
1229
     * {@inheritdoc}
1230
     */
1231
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
1232
    {
1233
        $unsigned      = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : '';
1234
        $autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : '';
1235
1236
        return $unsigned . $columnDef['integer_type'] . $autoincrement;
1237
    }
1238
1239
    /**
1240
     * {@inheritdoc}
1241
     */
1242
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1243
    {
1244
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1245
        $indexSql = [];
1246
1247
        if ( ! empty($options['uniqueConstraints'])) {
1248
            foreach ((array) $options['uniqueConstraints'] as $name => $definition) {
1249
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1250
            }
1251
        }
1252
1253
        if ( ! empty($options['indexes'])) {
1254
            /** @var \Doctrine\DBAL\Schema\Index $index */
1255
            foreach ((array) $options['indexes'] as $index) {
1256
                $indexSql[] = $this->getCreateIndexSQL($index, $tableName);
1257
            }
1258
        }
1259
1260
        if ( ! empty($options['primary'])) {
1261
            $flags = '';
1262
1263
            if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) {
1264
                $flags = ' CLUSTERED ';
1265
            }
1266
1267
            $columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')';
1268
        }
1269
1270
        if ( ! empty($options['foreignKeys'])) {
1271
            foreach ((array) $options['foreignKeys'] as $definition) {
1272
                $columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition);
1273
            }
1274
        }
1275
1276
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1277
        $check = $this->getCheckDeclarationSQL($columns);
1278
1279
        if ( ! empty($check)) {
1280
            $query .= ', ' . $check;
1281
        }
1282
1283
        $query .= ')';
1284
1285
        return array_merge([$query], $indexSql);
1286
    }
1287
1288
    /**
1289
     * {@inheritdoc}
1290
     */
1291
    protected function _getTransactionIsolationLevelSQL($level)
1292
    {
1293
        switch ($level) {
1294
            case TransactionIsolationLevel::READ_UNCOMMITTED:
1295
                return 0;
1296
            case TransactionIsolationLevel::READ_COMMITTED:
1297
                return 1;
1298
            case TransactionIsolationLevel::REPEATABLE_READ:
1299
                return 2;
1300
            case TransactionIsolationLevel::SERIALIZABLE:
1301
                return 3;
1302
            default:
1303
                throw new \InvalidArgumentException('Invalid isolation level:' . $level);
1304
        }
1305
    }
1306
1307
    /**
1308
     * {@inheritdoc}
1309
     */
1310
    protected function doModifyLimitQuery($query, $limit, $offset)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1311
    {
1312
        $limitOffsetClause = '';
1313
1314
        if ($limit > 0) {
1315
            $limitOffsetClause = 'TOP ' . $limit . ' ';
1316
        }
1317
1318
        if ($offset > 0) {
1319
            if ($limit == 0) {
1320
                $limitOffsetClause = 'TOP ALL ';
1321
            }
1322
1323
            $limitOffsetClause .= 'START AT ' . ($offset + 1) . ' ';
1324
        }
1325
1326
        if ($limitOffsetClause) {
1327
            return preg_replace('/^\s*(SELECT\s+(DISTINCT\s+)?)/i', '\1' . $limitOffsetClause, $query);
1328
        }
1329
1330
        return $query;
1331
    }
1332
1333
    /**
1334
     * Return the INDEX query section dealing with non-standard
1335
     * SQL Anywhere options.
1336
     *
1337
     * @param Index $index Index definition
1338
     *
1339
     * @return string
1340
     */
1341
    protected function getAdvancedIndexOptionsSQL(Index $index)
1342
    {
1343
        $sql = '';
1344
1345
        if ( ! $index->isPrimary() && $index->hasFlag('for_olap_workload')) {
1346
            $sql .= ' FOR OLAP WORKLOAD';
1347
        }
1348
1349
        return $sql;
1350
    }
1351
1352
    /**
1353
     * {@inheritdoc}
1354
     */
1355
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
1356
    {
1357
        return $fixed
1358
            ? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'
1359
            : 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')';
1360
    }
1361
1362
    /**
1363
     * Returns the SQL snippet for creating a table constraint.
1364
     *
1365
     * @param Constraint  $constraint The table constraint to create the SQL snippet for.
1366
     * @param string|null $name       The table constraint name to use if any.
1367
     *
1368
     * @return string
1369
     *
1370
     * @throws \InvalidArgumentException if the given table constraint type is not supported by this method.
1371
     */
1372
    protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null)
1373
    {
1374
        if ($constraint instanceof ForeignKeyConstraint) {
1375
            return $this->getForeignKeyDeclarationSQL($constraint);
1376
        }
1377
1378
        if ( ! $constraint instanceof Index) {
1379
            throw new \InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint));
1380
        }
1381
1382
        if ( ! $constraint->isPrimary() && ! $constraint->isUnique()) {
1383
            throw new \InvalidArgumentException(
1384
                'Can only create primary, unique or foreign key constraint declarations, no common index declarations ' .
1385
                'with getTableConstraintDeclarationSQL().'
1386
            );
1387
        }
1388
1389
        $constraintColumns = $constraint->getQuotedColumns($this);
1390
1391
        if (empty($constraintColumns)) {
1392
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1393
        }
1394
1395
        $sql   = '';
1396
        $flags = '';
1397
1398
        if ( ! empty($name)) {
1399
            $name = new Identifier($name);
1400
            $sql .= 'CONSTRAINT ' . $name->getQuotedName($this) . ' ';
1401
        }
1402
1403
        if ($constraint->hasFlag('clustered')) {
1404
            $flags = 'CLUSTERED ';
1405
        }
1406
1407
        if ($constraint->isPrimary()) {
1408
            return $sql . 'PRIMARY KEY ' . $flags . '('. $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
1409
        }
1410
1411
        return $sql . 'UNIQUE ' . $flags . '('. $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
1412
    }
1413
1414
    /**
1415
     * {@inheritdoc}
1416
     */
1417 View Code Duplication
    protected function getCreateIndexSQLFlags(Index $index)
1418
    {
1419
        $type = '';
1420
        if ($index->hasFlag('virtual')) {
1421
            $type .= 'VIRTUAL ';
1422
        }
1423
1424
        if ($index->isUnique()) {
1425
            $type .= 'UNIQUE ';
1426
        }
1427
1428
        if ($index->hasFlag('clustered')) {
1429
            $type .= 'CLUSTERED ';
1430
        }
1431
1432
        return $type;
1433
    }
1434
1435
    /**
1436
     * {@inheritdoc}
1437
     */
1438
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
1439
    {
1440
        return [
1441
            'ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)
1442
        ];
1443
    }
1444
1445
    /**
1446
     * {@inheritdoc}
1447
     */
1448
    protected function getReservedKeywordsClass()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1449
    {
1450
        return Keywords\SQLAnywhereKeywords::class;
1451
    }
1452
1453
    /**
1454
     * {@inheritdoc}
1455
     */
1456
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
1457
    {
1458
        return $fixed
1459
            ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')')
1460
            : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')');
1461
    }
1462
1463
    /**
1464
     * {@inheritdoc}
1465
     */
1466 View Code Duplication
    protected function initializeDoctrineTypeMappings()
1467
    {
1468
        $this->doctrineTypeMapping = [
1469
            'char' => 'string',
1470
            'long nvarchar' => 'text',
1471
            'long varchar' => 'text',
1472
            'nchar' => 'string',
1473
            'ntext' => 'text',
1474
            'nvarchar' => 'string',
1475
            'text' => 'text',
1476
            'uniqueidentifierstr' => 'guid',
1477
            'varchar' => 'string',
1478
            'xml' => 'text',
1479
            'bigint' => 'bigint',
1480
            'unsigned bigint' => 'bigint',
1481
            'bit' => 'boolean',
1482
            'decimal' => 'decimal',
1483
            'double' => 'float',
1484
            'float' => 'float',
1485
            'int' => 'integer',
1486
            'integer' => 'integer',
1487
            'unsigned int' => 'integer',
1488
            'numeric' => 'decimal',
1489
            'smallint' => 'smallint',
1490
            'unsigned smallint', 'smallint',
1491
            'tinyint' => 'smallint',
1492
            'unsigned tinyint', 'smallint',
1493
            'money' => 'decimal',
1494
            'smallmoney' => 'decimal',
1495
            'long varbit' => 'text',
1496
            'varbit' => 'string',
1497
            'date' => 'date',
1498
            'datetime' => 'datetime',
1499
            'smalldatetime' => 'datetime',
1500
            'time' => 'time',
1501
            'timestamp' => 'datetime',
1502
            'binary' => 'binary',
1503
            'image' => 'blob',
1504
            'long binary' => 'blob',
1505
            'uniqueidentifier' => 'guid',
1506
            'varbinary' => 'binary',
1507
        ];
1508
    }
1509
}
1510