Failed Conditions
Push — master ( 656579...2742cd )
by Marco
11:55
created

SQLAnywherePlatform::getAdvancedIndexOptionsSQL()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 4
nc 2
nop 1
crap 3
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\Connection;
23
use Doctrine\DBAL\DBALException;
24
use Doctrine\DBAL\LockMode;
25
use Doctrine\DBAL\Schema\Column;
26
use Doctrine\DBAL\Schema\ColumnDiff;
27
use Doctrine\DBAL\Schema\Constraint;
28
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
29
use Doctrine\DBAL\Schema\Identifier;
30
use Doctrine\DBAL\Schema\Index;
31
use Doctrine\DBAL\Schema\Table;
32
use Doctrine\DBAL\Schema\TableDiff;
33
34
/**
35
 * The SQLAnywherePlatform provides the behavior, features and SQL dialect of the
36
 * SAP Sybase SQL Anywhere 10 database platform.
37
 *
38
 * @author Steve Müller <[email protected]>
39
 * @link   www.doctrine-project.org
40
 * @since  2.5
41
 */
42
class SQLAnywherePlatform extends AbstractPlatform
43
{
44
    /**
45
     * @var integer
46
     */
47
    const FOREIGN_KEY_MATCH_SIMPLE = 1;
48
    /**
49
     * @var integer
50
     */
51
    const FOREIGN_KEY_MATCH_FULL = 2;
52
    /**
53
     * @var integer
54
     */
55
    const FOREIGN_KEY_MATCH_SIMPLE_UNIQUE = 129;
56
    /**
57
     * @var integer
58
     */
59
    const FOREIGN_KEY_MATCH_FULL_UNIQUE = 130;
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 28 View Code Duplication
    public function appendLockHint($fromClause, $lockMode)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
65
    {
66
        switch (true) {
67 28
            case $lockMode === LockMode::NONE:
68 4
                return $fromClause . ' WITH (NOLOCK)';
69
70 24
            case $lockMode === LockMode::PESSIMISTIC_READ:
71 4
                return $fromClause . ' WITH (UPDLOCK)';
72
73 20
            case $lockMode === LockMode::PESSIMISTIC_WRITE:
74 4
                return $fromClause . ' WITH (XLOCK)';
75
76
            default:
77 16
                return $fromClause;
78
        }
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     *
84
     * SQL Anywhere supports a maximum length of 128 bytes for identifiers.
85
     */
86 4
    public function fixSchemaElementName($schemaElementName)
87
    {
88 4
        $maxIdentifierLength = $this->getMaxIdentifierLength();
89
90 4
        if (strlen($schemaElementName) > $maxIdentifierLength) {
91 4
            return substr($schemaElementName, 0, $maxIdentifierLength);
92
        }
93
94 4
        return $schemaElementName;
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100 28
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
101
    {
102 28
        $query = '';
103
104 28
        if ($foreignKey->hasOption('match')) {
105 4
            $query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match'));
106
        }
107
108 28
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
109
110 28
        if ($foreignKey->hasOption('check_on_commit') && (boolean) $foreignKey->getOption('check_on_commit')) {
111 4
            $query .= ' CHECK ON COMMIT';
112
        }
113
114 28
        if ($foreignKey->hasOption('clustered') && (boolean) $foreignKey->getOption('clustered')) {
115 4
            $query .= ' CLUSTERED';
116
        }
117
118 28
        if ($foreignKey->hasOption('for_olap_workload') && (boolean) $foreignKey->getOption('for_olap_workload')) {
119 4
            $query .= ' FOR OLAP WORKLOAD';
120
        }
121
122 28
        return $query;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 60
    public function getAlterTableSQL(TableDiff $diff)
129
    {
130 60
        $sql          = [];
131 60
        $columnSql    = [];
132 60
        $commentsSQL  = [];
133 60
        $tableSql     = [];
134 60
        $alterClauses = [];
135
136
        /** @var \Doctrine\DBAL\Schema\Column $column */
137 60
        foreach ($diff->addedColumns as $column) {
138 16
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
139
                continue;
140
            }
141
142 16
            $alterClauses[] = $this->getAlterTableAddColumnClause($column);
143
144 16
            $comment = $this->getColumnComment($column);
145
146 16 View Code Duplication
            if (null !== $comment && '' !== $comment) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
147 4
                $commentsSQL[] = $this->getCommentOnColumnSQL(
148 4
                    $diff->getName($this)->getQuotedName($this),
149 4
                    $column->getQuotedName($this),
150 16
                    $comment
151
                );
152
            }
153
        }
154
155
        /** @var \Doctrine\DBAL\Schema\Column $column */
156 60
        foreach ($diff->removedColumns as $column) {
157 12
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
158
                continue;
159
            }
160
161 12
            $alterClauses[] = $this->getAlterTableRemoveColumnClause($column);
162
        }
163
164
        /** @var \Doctrine\DBAL\Schema\ColumnDiff $columnDiff */
165 60
        foreach ($diff->changedColumns as $columnDiff) {
166 32
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
167
                continue;
168
            }
169
170 32
            $alterClause = $this->getAlterTableChangeColumnClause($columnDiff);
171
172 32
            if (null !== $alterClause) {
173 20
                $alterClauses[] = $alterClause;
174
            }
175
176 32 View Code Duplication
            if ($columnDiff->hasChanged('comment')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177 12
                $column = $columnDiff->column;
178
179 12
                $commentsSQL[] = $this->getCommentOnColumnSQL(
180 12
                    $diff->getName($this)->getQuotedName($this),
181 12
                    $column->getQuotedName($this),
182 32
                    $this->getColumnComment($column)
183
                );
184
            }
185
        }
186
187 60 View Code Duplication
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188 16
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
189
                continue;
190
            }
191
192 16
            $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
193 16
                $this->getAlterTableRenameColumnClause($oldColumnName, $column);
194
        }
195
196 60
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
197 60
            if ( ! empty($alterClauses)) {
198 24
                $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . implode(", ", $alterClauses);
199
            }
200
201 60
            $sql = array_merge($sql, $commentsSQL);
202
203 60
            if ($diff->newName !== false) {
204 8
                $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' .
205 8
                    $this->getAlterTableRenameTableClause($diff->getNewName());
206
            }
207
208 60
            $sql = array_merge(
209 60
                $this->getPreAlterTableIndexForeignKeySQL($diff),
210 60
                $sql,
211 60
                $this->getPostAlterTableIndexForeignKeySQL($diff)
212
            );
213
        }
214
215 60
        return array_merge($sql, $tableSql, $columnSql);
216
    }
217
218
    /**
219
     * Returns the SQL clause for creating a column in a table alteration.
220
     *
221
     * @param Column $column The column to add.
222
     *
223
     * @return string
224
     */
225 16
    protected function getAlterTableAddColumnClause(Column $column)
226
    {
227 16
        return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
228
    }
229
230
    /**
231
     * Returns the SQL clause for altering a table.
232
     *
233
     * @param Identifier $tableName The quoted name of the table to alter.
234
     *
235
     * @return string
236
     */
237 32
    protected function getAlterTableClause(Identifier $tableName)
238
    {
239 32
        return 'ALTER TABLE ' . $tableName->getQuotedName($this);
240
    }
241
242
    /**
243
     * Returns the SQL clause for dropping a column in a table alteration.
244
     *
245
     * @param Column $column The column to drop.
246
     *
247
     * @return string
248
     */
249 12
    protected function getAlterTableRemoveColumnClause(Column $column)
250
    {
251 12
        return 'DROP ' . $column->getQuotedName($this);
252
    }
253
254
    /**
255
     * Returns the SQL clause for renaming a column in a table alteration.
256
     *
257
     * @param string $oldColumnName The quoted name of the column to rename.
258
     * @param Column $column        The column to rename to.
259
     *
260
     * @return string
261
     */
262 16
    protected function getAlterTableRenameColumnClause($oldColumnName, Column $column)
263
    {
264 16
        $oldColumnName = new Identifier($oldColumnName);
265
266 16
        return 'RENAME ' . $oldColumnName->getQuotedName($this) .' TO ' . $column->getQuotedName($this);
267
    }
268
269
    /**
270
     * Returns the SQL clause for renaming a table in a table alteration.
271
     *
272
     * @param Identifier $newTableName The quoted name of the table to rename to.
273
     *
274
     * @return string
275
     */
276 8
    protected function getAlterTableRenameTableClause(Identifier $newTableName)
277
    {
278 8
        return 'RENAME ' . $newTableName->getQuotedName($this);
279
    }
280
281
    /**
282
     * Returns the SQL clause for altering a column in a table alteration.
283
     *
284
     * This method returns null in case that only the column comment has changed.
285
     * Changes in column comments have to be handled differently.
286
     *
287
     * @param ColumnDiff $columnDiff The diff of the column to alter.
288
     *
289
     * @return string|null
290
     */
291 32
    protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff)
292
    {
293 32
        $column = $columnDiff->column;
294
295
        // Do not return alter clause if only comment has changed.
296 32
        if ( ! ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1)) {
297
            $columnAlterationClause = 'ALTER ' .
298 20
                $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
299
300 20
            if ($columnDiff->hasChanged('default') && null === $column->getDefault()) {
301
                $columnAlterationClause .= ', ALTER ' . $column->getQuotedName($this) . ' DROP DEFAULT';
302
            }
303
304 20
            return $columnAlterationClause;
305
        }
306
307 12
        return null;
308
    }
309
310
    /**
311
     * {@inheritdoc}
312
     */
313 4
    public function getBigIntTypeDeclarationSQL(array $columnDef)
314
    {
315 4
        $columnDef['integer_type'] = 'BIGINT';
316
317 4
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
318
    }
319
320
    /**
321
     * {@inheritdoc}
322
     */
323 8
    public function getBinaryDefaultLength()
324
    {
325 8
        return 1;
326
    }
327
328
    /**
329
     * {@inheritdoc}
330
     */
331 8
    public function getBinaryMaxLength()
332
    {
333 8
        return 32767;
334
    }
335
336
    /**
337
     * {@inheritdoc}
338
     */
339 8
    public function getBlobTypeDeclarationSQL(array $field)
340
    {
341 8
        return 'LONG BINARY';
342
    }
343
344
    /**
345
     * {@inheritdoc}
346
     *
347
     * BIT type columns require an explicit NULL declaration
348
     * in SQL Anywhere if they shall be nullable.
349
     * Otherwise by just omitting the NOT NULL clause,
350
     * SQL Anywhere will declare them NOT NULL nonetheless.
351
     */
352 8
    public function getBooleanTypeDeclarationSQL(array $columnDef)
353
    {
354 8
        $nullClause = isset($columnDef['notnull']) && (boolean) $columnDef['notnull'] === false ? ' NULL' : '';
355
356 8
        return 'BIT' . $nullClause;
357
    }
358
359
    /**
360
     * {@inheritdoc}
361
     */
362 12
    public function getClobTypeDeclarationSQL(array $field)
363
    {
364 12
        return 'TEXT';
365
    }
366
367
    /**
368
     * {@inheritdoc}
369
     */
370 32 View Code Duplication
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372 32
        $tableName = new Identifier($tableName);
373 32
        $columnName = new Identifier($columnName);
374 32
        $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment);
375
376 32
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . '.' . $columnName->getQuotedName($this) .
377 32
            " IS $comment";
378
    }
379
380
    /**
381
     * {@inheritdoc}
382
     */
383 4
    public function getConcatExpression()
384
    {
385 4
        return 'STRING(' . implode(', ', (array) func_get_args()) . ')';
386
    }
387
388
    /**
389
     * {@inheritdoc}
390
     */
391 12
    public function getCreateConstraintSQL(Constraint $constraint, $table)
392
    {
393 12
        if ($constraint instanceof ForeignKeyConstraint) {
394 4
            return $this->getCreateForeignKeySQL($constraint, $table);
395
        }
396
397 12
        if ($table instanceof Table) {
398 4
            $table = $table->getQuotedName($this);
399
        }
400
401 12
        return 'ALTER TABLE ' . $table .
402 12
               ' ADD ' . $this->getTableConstraintDeclarationSQL($constraint, $constraint->getQuotedName($this));
403
    }
404
405
    /**
406
     * {@inheritdoc}
407
     */
408 4
    public function getCreateDatabaseSQL($database)
409
    {
410 4
        $database = new Identifier($database);
411
412 4
        return "CREATE DATABASE '" . $database->getName() . "'";
413
    }
414
415
    /**
416
     * {@inheritdoc}
417
     *
418
     * Appends SQL Anywhere specific flags if given.
419
     */
420 33
    public function getCreateIndexSQL(Index $index, $table)
421
    {
422 33
        return parent::getCreateIndexSQL($index, $table). $this->getAdvancedIndexOptionsSQL($index);
423
    }
424
425
    /**
426
     * {@inheritdoc}
427
     */
428 6
    public function getCreatePrimaryKeySQL(Index $index, $table)
429
    {
430 6
        if ($table instanceof Table) {
431 4
            $table = $table->getQuotedName($this);
432
        }
433
434 6
        return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index);
435
    }
436
437
    /**
438
     * {@inheritdoc}
439
     */
440 4
    public function getCreateTemporaryTableSnippetSQL()
441
    {
442 4
        return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE';
443
    }
444
445
    /**
446
     * {@inheritdoc}
447
     */
448 4
    public function getCreateViewSQL($name, $sql)
449
    {
450 4
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
451
    }
452
453
    /**
454
     * {@inheritdoc}
455
     */
456 8
    public function getCurrentDateSQL()
457
    {
458 8
        return 'CURRENT DATE';
459
    }
460
461
    /**
462
     * {@inheritdoc}
463
     */
464 4
    public function getCurrentTimeSQL()
465
    {
466 4
        return 'CURRENT TIME';
467
    }
468
469
    /**
470
     * {@inheritdoc}
471
     */
472 8
    public function getCurrentTimestampSQL()
473
    {
474 8
        return 'CURRENT TIMESTAMP';
475
    }
476
477
    /**
478
     * {@inheritdoc}
479
     */
480 4 View Code Duplication
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
481
    {
482 4
        $factorClause = '';
483
484 4
        if ('-' === $operator) {
485 4
            $factorClause = '-1 * ';
486
        }
487
488 4
        return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')';
489
    }
490
491
    /**
492
     * {@inheritdoc}
493
     */
494 4
    public function getDateDiffExpression($date1, $date2)
495
    {
496 4
        return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')';
497
    }
498
499
    /**
500
     * {@inheritdoc}
501
     */
502 6
    public function getDateTimeFormatString()
503
    {
504 6
        return 'Y-m-d H:i:s.u';
505
    }
506
507
    /**
508
     * {@inheritdoc}
509
     */
510 4
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
511
    {
512 4
        return 'DATETIME';
513
    }
514
515
    /**
516
     * {@inheritdoc}
517
     */
518 2
    public function getDateTimeTzFormatString()
519
    {
520 2
        return $this->getDateTimeFormatString();
521
    }
522
523
    /**
524
     * {@inheritdoc}
525
     */
526 4
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
527
    {
528 4
        return 'DATE';
529
    }
530
531
    /**
532
     * {@inheritdoc}
533
     */
534 4
    public function getDefaultTransactionIsolationLevel()
535
    {
536 4
        return Connection::TRANSACTION_READ_UNCOMMITTED;
537
    }
538
539
    /**
540
     * {@inheritdoc}
541
     */
542 4
    public function getDropDatabaseSQL($database)
543
    {
544 4
        $database = new Identifier($database);
545
546 4
        return "DROP DATABASE '" . $database->getName() . "'";
547
    }
548
549
    /**
550
     * {@inheritdoc}
551
     */
552 12
    public function getDropIndexSQL($index, $table = null)
553
    {
554 12
        if ($index instanceof Index) {
555 4
            $index = $index->getQuotedName($this);
556
        }
557
558 12
        if ( ! is_string($index)) {
559 4
            throw new \InvalidArgumentException(
560
                'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' .
561 4
                '\Doctrine\DBAL\Schema\Index.'
562
            );
563
        }
564
565 8
        if ( ! isset($table)) {
566 4
            return 'DROP INDEX ' . $index;
567
        }
568
569 8
        if ($table instanceof Table) {
570 4
            $table = $table->getQuotedName($this);
571
        }
572
573 8
        if ( ! is_string($table)) {
574 4
            throw new \InvalidArgumentException(
575
                'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' .
576 4
                '\Doctrine\DBAL\Schema\Table.'
577
            );
578
        }
579
580 4
        return 'DROP INDEX ' . $table . '.' . $index;
581
    }
582
583
    /**
584
     * {@inheritdoc}
585
     */
586 4
    public function getDropViewSQL($name)
587
    {
588 4
        return 'DROP VIEW ' . $name;
589
    }
590
591
    /**
592
     * {@inheritdoc}
593
     */
594 40
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
595
    {
596 40
        $sql              = '';
597 40
        $foreignKeyName   = $foreignKey->getName();
598 40
        $localColumns     = $foreignKey->getQuotedLocalColumns($this);
599 40
        $foreignColumns   = $foreignKey->getQuotedForeignColumns($this);
600 40
        $foreignTableName = $foreignKey->getQuotedForeignTableName($this);
601
602 40
        if ( ! empty($foreignKeyName)) {
603 24
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
604
        }
605
606 40
        if (empty($localColumns)) {
607 4
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
608
        }
609
610 36
        if (empty($foreignColumns)) {
611 4
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
612
        }
613
614 32
        if (empty($foreignTableName)) {
615 4
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
616
        }
617
618 28
        if ($foreignKey->hasOption('notnull') && (boolean) $foreignKey->getOption('notnull')) {
619 4
            $sql .= 'NOT NULL ';
620
        }
621
622
        return $sql .
623 28
            'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' .
624 28
            'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) .
625 28
            ' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')';
626
    }
627
628
    /**
629
     * Returns foreign key MATCH clause for given type.
630
     *
631
     * @param integer $type The foreign key match type
632
     *
633
     * @return string
634
     *
635
     * @throws \InvalidArgumentException if unknown match type given
636
     */
637 12
    public function getForeignKeyMatchClauseSQL($type)
638
    {
639 12
        switch ((int) $type) {
640 12
            case self::FOREIGN_KEY_MATCH_SIMPLE:
641 4
                return 'SIMPLE';
642
                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...
643 12
            case self::FOREIGN_KEY_MATCH_FULL:
644 4
                return 'FULL';
645
                break;
646 12
            case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE:
647 8
                return 'UNIQUE SIMPLE';
648
                break;
649 8
            case self::FOREIGN_KEY_MATCH_FULL_UNIQUE:
650 4
                return 'UNIQUE FULL';
651
            default:
652 4
                throw new \InvalidArgumentException('Invalid foreign key match type: ' . $type);
653
        }
654
    }
655
656
    /**
657
     * {@inheritdoc}
658
     */
659 32
    public function getForeignKeyReferentialActionSQL($action)
660
    {
661
        // NO ACTION is not supported, therefore falling back to RESTRICT.
662 32
        if (strtoupper($action) === 'NO ACTION') {
663 4
            return 'RESTRICT';
664
        }
665
666 28
        return parent::getForeignKeyReferentialActionSQL($action);
667
    }
668
669
    /**
670
     * {@inheritdoc}
671
     */
672 4
    public function getForUpdateSQL()
673
    {
674 4
        return '';
675
    }
676
677
    /**
678
     * {@inheritdoc}
679
     */
680 4
    public function getGuidExpression()
681
    {
682 4
        return 'NEWID()';
683
    }
684
685
    /**
686
     * {@inheritdoc}
687
     */
688 8
    public function getGuidTypeDeclarationSQL(array $field)
689
    {
690 8
        return 'UNIQUEIDENTIFIER';
691
    }
692
693
    /**
694
     * {@inheritdoc}
695
     */
696 8
    public function getIndexDeclarationSQL($name, Index $index)
697
    {
698
        // Index declaration in statements like CREATE TABLE is not supported.
699 8
        throw DBALException::notSupported(__METHOD__);
700
    }
701
702
    /**
703
     * {@inheritdoc}
704
     */
705 44
    public function getIntegerTypeDeclarationSQL(array $columnDef)
706
    {
707 44
        $columnDef['integer_type'] = 'INT';
708
709 44
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
710
    }
711
712
    /**
713
     * {@inheritdoc}
714
     */
715
    public function getListDatabasesSQL()
716
    {
717
        return 'SELECT db_name(number) AS name FROM sa_db_list()';
718
    }
719
720
    /**
721
     * {@inheritdoc}
722
     */
723 4
    public function getListTableColumnsSQL($table, $database = null)
724
    {
725 4
        $user = 'USER_NAME()';
726
727 4 View Code Duplication
        if (strpos($table, '.') !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
728 4
            list($user, $table) = explode('.', $table);
729 4
            $user = $this->quoteStringLiteral($user);
730
        }
731
732
        return "SELECT    col.column_name,
733
                          COALESCE(def.user_type_name, def.domain_name) AS 'type',
734
                          def.declared_width AS 'length',
735
                          def.scale,
736
                          CHARINDEX('unsigned', def.domain_name) AS 'unsigned',
737
                          IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull',
738
                          col.\"default\",
739
                          def.is_autoincrement AS 'autoincrement',
740
                          rem.remarks AS 'comment'
741 4
                FROM      sa_describe_query('SELECT * FROM \"$table\"') AS def
742
                JOIN      SYS.SYSTABCOL AS col
743
                ON        col.table_id = def.base_table_id AND col.column_id = def.base_column_id
744
                LEFT JOIN SYS.SYSREMARK AS rem
745
                ON        col.object_id = rem.object_id
746 4
                WHERE     def.base_owner_name = $user
747
                ORDER BY  def.base_column_id ASC";
748
    }
749
750
    /**
751
     * {@inheritdoc}
752
     *
753
     * @todo Where is this used? Which information should be retrieved?
754
     */
755 8 View Code Duplication
    public function getListTableConstraintsSQL($table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
756
    {
757 8
        $user = '';
758
759 8
        if (strpos($table, '.') !== false) {
760 4
            list($user, $table) = explode('.', $table);
761 4
            $user = $this->quoteStringLiteral($user);
762 4
            $table = $this->quoteStringLiteral($table);
763
        } else {
764 4
            $table = $this->quoteStringLiteral($table);
765
        }
766
767
        return "SELECT con.*
768
                FROM   SYS.SYSCONSTRAINT AS con
769
                JOIN   SYS.SYSTAB AS tab ON con.table_object_id = tab.object_id
770 8
                WHERE  tab.table_name = $table
771 8
                AND    tab.creator = USER_ID($user)";
772
    }
773
774
    /**
775
     * {@inheritdoc}
776
     */
777 8 View Code Duplication
    public function getListTableForeignKeysSQL($table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
778
    {
779 8
        $user = '';
780
781 8
        if (strpos($table, '.') !== false) {
782 4
            list($user, $table) = explode('.', $table);
783 4
            $user = $this->quoteStringLiteral($user);
784 4
            $table = $this->quoteStringLiteral($table);
785
        } else {
786 4
            $table = $this->quoteStringLiteral($table);
787
        }
788
789
        return "SELECT    fcol.column_name AS local_column,
790
                          ptbl.table_name AS foreign_table,
791
                          pcol.column_name AS foreign_column,
792
                          idx.index_name,
793
                          IF fk.nulls = 'N'
794
                              THEN 1
795
                              ELSE NULL
796
                          ENDIF AS notnull,
797
                          CASE ut.referential_action
798
                              WHEN 'C' THEN 'CASCADE'
799
                              WHEN 'D' THEN 'SET DEFAULT'
800
                              WHEN 'N' THEN 'SET NULL'
801
                              WHEN 'R' THEN 'RESTRICT'
802
                              ELSE NULL
803
                          END AS  on_update,
804
                          CASE dt.referential_action
805
                              WHEN 'C' THEN 'CASCADE'
806
                              WHEN 'D' THEN 'SET DEFAULT'
807
                              WHEN 'N' THEN 'SET NULL'
808
                              WHEN 'R' THEN 'RESTRICT'
809
                              ELSE NULL
810
                          END AS on_delete,
811
                          IF fk.check_on_commit = 'Y'
812
                              THEN 1
813
                              ELSE NULL
814
                          ENDIF AS check_on_commit, -- check_on_commit flag
815
                          IF ftbl.clustered_index_id = idx.index_id
816
                              THEN 1
817
                              ELSE NULL
818
                          ENDIF AS 'clustered', -- clustered flag
819
                          IF fk.match_type = 0
820
                              THEN NULL
821
                              ELSE fk.match_type
822
                          ENDIF AS 'match', -- match option
823
                          IF pidx.max_key_distance = 1
824
                              THEN 1
825
                              ELSE NULL
826
                          ENDIF AS for_olap_workload -- for_olap_workload flag
827
                FROM      SYS.SYSFKEY AS fk
828
                JOIN      SYS.SYSIDX AS idx
829
                ON        fk.foreign_table_id = idx.table_id
830
                AND       fk.foreign_index_id = idx.index_id
831
                JOIN      SYS.SYSPHYSIDX pidx
832
                ON        idx.table_id = pidx.table_id
833
                AND       idx.phys_index_id = pidx.phys_index_id
834
                JOIN      SYS.SYSTAB AS ptbl
835
                ON        fk.primary_table_id = ptbl.table_id
836
                JOIN      SYS.SYSTAB AS ftbl
837
                ON        fk.foreign_table_id = ftbl.table_id
838
                JOIN      SYS.SYSIDXCOL AS idxcol
839
                ON        idx.table_id = idxcol.table_id
840
                AND       idx.index_id = idxcol.index_id
841
                JOIN      SYS.SYSTABCOL AS pcol
842
                ON        ptbl.table_id = pcol.table_id
843
                AND       idxcol.primary_column_id = pcol.column_id
844
                JOIN      SYS.SYSTABCOL AS fcol
845
                ON        ftbl.table_id = fcol.table_id
846
                AND       idxcol.column_id = fcol.column_id
847
                LEFT JOIN SYS.SYSTRIGGER ut
848
                ON        fk.foreign_table_id = ut.foreign_table_id
849
                AND       fk.foreign_index_id = ut.foreign_key_id
850
                AND       ut.event = 'C'
851
                LEFT JOIN SYS.SYSTRIGGER dt
852
                ON        fk.foreign_table_id = dt.foreign_table_id
853
                AND       fk.foreign_index_id = dt.foreign_key_id
854
                AND       dt.event = 'D'
855 8
                WHERE     ftbl.table_name = $table
856 8
                AND       ftbl.creator = USER_ID($user)
857
                ORDER BY  fk.foreign_index_id ASC, idxcol.sequence ASC";
858
    }
859
860
    /**
861
     * {@inheritdoc}
862
     */
863 8 View Code Duplication
    public function getListTableIndexesSQL($table, $currentDatabase = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
864
    {
865 8
        $user = '';
866
867 8
        if (strpos($table, '.') !== false) {
868 4
            list($user, $table) = explode('.', $table);
869 4
            $user = $this->quoteStringLiteral($user);
870 4
            $table = $this->quoteStringLiteral($table);
871
        } else {
872 4
            $table = $this->quoteStringLiteral($table);
873
        }
874
875
        return "SELECT   idx.index_name AS key_name,
876
                         IF idx.index_category = 1
877
                             THEN 1
878
                             ELSE 0
879
                         ENDIF AS 'primary',
880
                         col.column_name,
881
                         IF idx.\"unique\" IN(1, 2, 5)
882
                             THEN 0
883
                             ELSE 1
884
                         ENDIF AS non_unique,
885
                         IF tbl.clustered_index_id = idx.index_id
886
                             THEN 1
887
                             ELSE NULL
888
                         ENDIF AS 'clustered', -- clustered flag
889
                         IF idx.\"unique\" = 5
890
                             THEN 1
891
                             ELSE NULL
892
                         ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag
893
                         IF pidx.max_key_distance = 1
894
                              THEN 1
895
                              ELSE NULL
896
                          ENDIF AS for_olap_workload -- for_olap_workload flag
897
                FROM     SYS.SYSIDX AS idx
898
                JOIN     SYS.SYSPHYSIDX pidx
899
                ON       idx.table_id = pidx.table_id
900
                AND      idx.phys_index_id = pidx.phys_index_id
901
                JOIN     SYS.SYSIDXCOL AS idxcol
902
                ON       idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id
903
                JOIN     SYS.SYSTABCOL AS col
904
                ON       idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id
905
                JOIN     SYS.SYSTAB AS tbl
906
                ON       idx.table_id = tbl.table_id
907 8
                WHERE    tbl.table_name = $table
908 8
                AND      tbl.creator = USER_ID($user)
909
                AND      idx.index_category != 2 -- exclude indexes implicitly created by foreign key constraints
910
                ORDER BY idx.index_id ASC, idxcol.sequence ASC";
911
    }
912
913
    /**
914
     * {@inheritdoc}
915
     */
916
    public function getListTablesSQL()
917
    {
918
        return "SELECT   tbl.table_name
919
                FROM     SYS.SYSTAB AS tbl
920
                JOIN     SYS.SYSUSER AS usr ON tbl.creator = usr.user_id
921
                JOIN     dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id
922
                WHERE    tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP'
923
                AND      usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
924
                AND      obj.type = 'U' -- user created tables only
925
                ORDER BY tbl.table_name ASC";
926
    }
927
928
    /**
929
     * {@inheritdoc}
930
     *
931
     * @todo Where is this used? Which information should be retrieved?
932
     */
933
    public function getListUsersSQL()
934
    {
935
        return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC';
936
    }
937
938
    /**
939
     * {@inheritdoc}
940
     */
941
    public function getListViewsSQL($database)
942
    {
943
        return "SELECT   tbl.table_name, v.view_def
944
                FROM     SYS.SYSVIEW v
945
                JOIN     SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id
946
                JOIN     SYS.SYSUSER usr ON tbl.creator = usr.user_id
947
                JOIN     dbo.SYSOBJECTS obj ON tbl.object_id = obj.id
948
                WHERE    usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users
949
                ORDER BY tbl.table_name ASC";
950
    }
951
952
    /**
953
     * {@inheritdoc}
954
     */
955 4 View Code Duplication
    public function getLocateExpression($str, $substr, $startPos = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
956
    {
957 4
        if ($startPos == false) {
958 4
            return 'LOCATE(' . $str . ', ' . $substr . ')';
959
        }
960
961 4
        return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')';
962
    }
963
964
    /**
965
     * {@inheritdoc}
966
     */
967 8
    public function getMaxIdentifierLength()
968
    {
969 8
        return 128;
970
    }
971
972
    /**
973
     * {@inheritdoc}
974
     */
975 4
    public function getMd5Expression($column)
976
    {
977 4
        return "HASH(" . $column . ", 'MD5')";
978
    }
979
980
    /**
981
     * {@inheritdoc}
982
     */
983 12
    public function getName()
984
    {
985 12
        return 'sqlanywhere';
986
    }
987
988
    /**
989
     * Obtain DBMS specific SQL code portion needed to set a primary key
990
     * declaration to be used in statements like ALTER TABLE.
991
     *
992
     * @param Index  $index Index definition
993
     * @param string $name  Name of the primary key
994
     *
995
     * @return string DBMS specific SQL code portion needed to set a primary key
996
     *
997
     * @throws \InvalidArgumentException if the given index is not a primary key.
998
     */
999 14
    public function getPrimaryKeyDeclarationSQL(Index $index, $name = null)
1000
    {
1001 14
        if ( ! $index->isPrimary()) {
1002
            throw new \InvalidArgumentException(
1003
                'Can only create primary key declarations with getPrimaryKeyDeclarationSQL()'
1004
            );
1005
        }
1006
1007 14
        return $this->getTableConstraintDeclarationSQL($index, $name);
1008
    }
1009
1010
    /**
1011
     * {@inheritdoc}
1012
     */
1013 8
    public function getSetTransactionIsolationSQL($level)
1014
    {
1015 8
        return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level);
1016
    }
1017
1018
    /**
1019
     * {@inheritdoc}
1020
     */
1021 4
    public function getSmallIntTypeDeclarationSQL(array $columnDef)
1022
    {
1023 4
        $columnDef['integer_type'] = 'SMALLINT';
1024
1025 4
        return $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
1026
    }
1027
1028
    /**
1029
     * Returns the SQL statement for starting an existing database.
1030
     *
1031
     * In SQL Anywhere you can start and stop databases on a
1032
     * database server instance.
1033
     * This is a required statement after having created a new database
1034
     * as it has to be explicitly started to be usable.
1035
     * SQL Anywhere does not automatically start a database after creation!
1036
     *
1037
     * @param string $database Name of the database to start.
1038
     *
1039
     * @return string
1040
     */
1041 4
    public function getStartDatabaseSQL($database)
1042
    {
1043 4
        $database = new Identifier($database);
1044
1045 4
        return "START DATABASE '" . $database->getName() . "' AUTOSTOP OFF";
1046
    }
1047
1048
    /**
1049
     * Returns the SQL statement for stopping a running database.
1050
     *
1051
     * In SQL Anywhere you can start and stop databases on a
1052
     * database server instance.
1053
     * This is a required statement before dropping an existing database
1054
     * as it has to be explicitly stopped before it can be dropped.
1055
     *
1056
     * @param string $database Name of the database to stop.
1057
     *
1058
     * @return string
1059
     */
1060 4
    public function getStopDatabaseSQL($database)
1061
    {
1062 4
        $database = new Identifier($database);
1063
1064 4
        return 'STOP DATABASE "' . $database->getName() . '" UNCONDITIONALLY';
1065
    }
1066
1067
    /**
1068
     * {@inheritdoc}
1069
     */
1070 4 View Code Duplication
    public function getSubstringExpression($value, $from, $length = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1071
    {
1072 4
        if (null === $length) {
1073 4
            return 'SUBSTRING(' . $value . ', ' . $from . ')';
1074
        }
1075
1076 4
        return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')';
1077
    }
1078
1079
    /**
1080
     * {@inheritdoc}
1081
     */
1082 8
    public function getTemporaryTableSQL()
1083
    {
1084 8
        return 'GLOBAL TEMPORARY';
1085
    }
1086
1087
    /**
1088
     * {@inheritdoc}
1089
     */
1090 4
    public function getTimeFormatString()
1091
    {
1092 4
        return 'H:i:s.u';
1093
    }
1094
1095
    /**
1096
     * {@inheritdoc}
1097
     */
1098 4
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
1099
    {
1100 4
        return 'TIME';
1101
    }
1102
1103
    /**
1104
     * {@inheritdoc}
1105
     */
1106 4
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
1107
    {
1108 4
        if ( ! $char) {
1109
            switch ($pos) {
1110 4
                case self::TRIM_LEADING:
1111 4
                    return $this->getLtrimExpression($str);
1112 4
                case self::TRIM_TRAILING:
1113 4
                    return $this->getRtrimExpression($str);
1114
                default:
1115 4
                    return 'TRIM(' . $str . ')';
1116
            }
1117
        }
1118
1119 4
        $pattern = "'%[^' + $char + ']%'";
1120
1121
        switch ($pos) {
1122 4 View Code Duplication
            case self::TRIM_LEADING:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1123 4
                return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))';
1124 4 View Code Duplication
            case self::TRIM_TRAILING:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1125 4
                return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))';
1126
            default:
1127
                return
1128 4
                    'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' .
1129 4
                    'PATINDEX(' . $pattern . ', REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))';
1130
        }
1131
    }
1132
1133
    /**
1134
     * {@inheritdoc}
1135
     */
1136 8
    public function getTruncateTableSQL($tableName, $cascade = false)
1137
    {
1138 8
        $tableIdentifier = new Identifier($tableName);
1139
1140 8
        return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this);
1141
    }
1142
1143
    /**
1144
     * {@inheritdoc}
1145
     */
1146 16
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
1147
    {
1148 16
        if ($index->isPrimary()) {
1149
            throw new \InvalidArgumentException(
1150
                'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().'
1151
            );
1152
        }
1153
1154 16
        if ( ! $index->isUnique()) {
1155
            throw new \InvalidArgumentException(
1156
                'Can only create unique constraint declarations, no common index declarations with ' .
1157
                'getUniqueConstraintDeclarationSQL().'
1158
            );
1159
        }
1160
1161 16
        return $this->getTableConstraintDeclarationSQL($index, $name);
1162
    }
1163
1164
    /**
1165
     * {@inheritdoc}
1166
     */
1167 16
    public function getVarcharDefaultLength()
1168
    {
1169 16
        return 1;
1170
    }
1171
1172
    /**
1173
     * {@inheritdoc}
1174
     */
1175 52
    public function getVarcharMaxLength()
1176
    {
1177 52
        return 32767;
1178
    }
1179
1180
    /**
1181
     * {@inheritdoc}
1182
     */
1183 180
    public function hasNativeGuidType()
1184
    {
1185 180
        return true;
1186
    }
1187
1188
    /**
1189
     * {@inheritdoc}
1190
     */
1191 4
    public function prefersIdentityColumns()
1192
    {
1193 4
        return true;
1194
    }
1195
1196
    /**
1197
     * {@inheritdoc}
1198
     */
1199 52
    public function supportsCommentOnStatement()
1200
    {
1201 52
        return true;
1202
    }
1203
1204
    /**
1205
     * {@inheritdoc}
1206
     */
1207 4
    public function supportsIdentityColumns()
1208
    {
1209 4
        return true;
1210
    }
1211
1212
    /**
1213
     * {@inheritdoc}
1214
     */
1215 44
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
1216
    {
1217 44
        $unsigned      = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : '';
1218 44
        $autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : '';
1219
1220 44
        return $unsigned . $columnDef['integer_type'] . $autoincrement;
1221
    }
1222
1223
    /**
1224
     * {@inheritdoc}
1225
     */
1226 48
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1227
    {
1228 48
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1229 48
        $indexSql = [];
1230
1231 48
        if ( ! empty($options['uniqueConstraints'])) {
1232
            foreach ((array) $options['uniqueConstraints'] as $name => $definition) {
1233
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1234
            }
1235
        }
1236
1237 48
        if ( ! empty($options['indexes'])) {
1238
            /** @var \Doctrine\DBAL\Schema\Index $index */
1239 16
            foreach ((array) $options['indexes'] as $index) {
1240 16
                $indexSql[] = $this->getCreateIndexSQL($index, $tableName);
1241
            }
1242
        }
1243
1244 48 View Code Duplication
        if ( ! empty($options['primary'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1245 24
            $flags = '';
1246
1247 24
            if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) {
1248
                $flags = ' CLUSTERED ';
1249
            }
1250
1251 24
            $columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')';
1252
        }
1253
1254 48
        if ( ! empty($options['foreignKeys'])) {
1255 8
            foreach ((array) $options['foreignKeys'] as $definition) {
1256 8
                $columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition);
1257
            }
1258
        }
1259
1260 48
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1261 48
        $check = $this->getCheckDeclarationSQL($columns);
1262
1263 48
        if ( ! empty($check)) {
1264 4
            $query .= ', ' . $check;
1265
        }
1266
1267 48
        $query .= ')';
1268
1269 48
        return array_merge([$query], $indexSql);
1270
    }
1271
1272
    /**
1273
     * {@inheritdoc}
1274
     */
1275 8
    protected function _getTransactionIsolationLevelSQL($level)
1276
    {
1277
        switch ($level) {
1278 8
            case Connection::TRANSACTION_READ_UNCOMMITTED:
1279 4
                return 0;
1280 8
            case Connection::TRANSACTION_READ_COMMITTED:
1281 4
                return 1;
1282 8
            case Connection::TRANSACTION_REPEATABLE_READ:
1283 4
                return 2;
1284 8
            case Connection::TRANSACTION_SERIALIZABLE:
1285 4
                return 3;
1286
            default:
1287 4
                throw new \InvalidArgumentException('Invalid isolation level:' . $level);
1288
        }
1289
    }
1290
1291
    /**
1292
     * {@inheritdoc}
1293
     */
1294 16
    protected function doModifyLimitQuery($query, $limit, $offset)
1295
    {
1296 16
        $limitOffsetClause = '';
1297
1298 16
        if ($limit > 0) {
1299 16
            $limitOffsetClause = 'TOP ' . $limit . ' ';
1300
        }
1301
1302 16
        if ($offset > 0) {
1303 4
            if ($limit == 0) {
1304 4
                $limitOffsetClause = 'TOP ALL ';
1305
            }
1306
1307 4
            $limitOffsetClause .= 'START AT ' . ($offset + 1) . ' ';
1308
        }
1309
1310 16
        if ($limitOffsetClause) {
1311 16
            return preg_replace('/^\s*(SELECT\s+(DISTINCT\s+)?)/i', '\1' . $limitOffsetClause, $query);
1312
        }
1313
1314
        return $query;
1315
    }
1316
1317
    /**
1318
     * Return the INDEX query section dealing with non-standard
1319
     * SQL Anywhere options.
1320
     *
1321
     * @param Index $index Index definition
1322
     *
1323
     * @return string
1324
     */
1325 32
    protected function getAdvancedIndexOptionsSQL(Index $index)
1326
    {
1327 32
        $sql = '';
1328
1329 32
        if ( ! $index->isPrimary() && $index->hasFlag('for_olap_workload')) {
1330 4
            $sql .= ' FOR OLAP WORKLOAD';
1331
        }
1332
1333 32
        return $sql;
1334
    }
1335
1336
    /**
1337
     * {@inheritdoc}
1338
     */
1339 4
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
1340
    {
1341 4
        return $fixed
1342 4
            ? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'
1343 4
            : 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')';
1344
    }
1345
1346
    /**
1347
     * Returns the SQL snippet for creating a table constraint.
1348
     *
1349
     * @param Constraint  $constraint The table constraint to create the SQL snippet for.
1350
     * @param string|null $name       The table constraint name to use if any.
1351
     *
1352
     * @return string
1353
     *
1354
     * @throws \InvalidArgumentException if the given table constraint type is not supported by this method.
1355
     */
1356 42
    protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null)
1357
    {
1358 42
        if ($constraint instanceof ForeignKeyConstraint) {
1359
            return $this->getForeignKeyDeclarationSQL($constraint);
1360
        }
1361
1362 42
        if ( ! $constraint instanceof Index) {
1363 4
            throw new \InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint));
1364
        }
1365
1366 38
        if ( ! $constraint->isPrimary() && ! $constraint->isUnique()) {
1367 4
            throw new \InvalidArgumentException(
1368
                'Can only create primary, unique or foreign key constraint declarations, no common index declarations ' .
1369 4
                'with getTableConstraintDeclarationSQL().'
1370
            );
1371
        }
1372
1373 34
        $constraintColumns = $constraint->getQuotedColumns($this);
1374
1375 34
        if (empty($constraintColumns)) {
1376 8
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1377
        }
1378
1379 26
        $sql   = '';
1380 26
        $flags = '';
1381
1382 26
        if ( ! empty($name)) {
1383 20
            $name = new Identifier($name);
1384 20
            $sql .= 'CONSTRAINT ' . $name->getQuotedName($this) . ' ';
1385
        }
1386
1387 26
        if ($constraint->hasFlag('clustered')) {
1388 12
            $flags = 'CLUSTERED ';
1389
        }
1390
1391 26
        if ($constraint->isPrimary()) {
1392 14
            return $sql . 'PRIMARY KEY ' . $flags . '('. $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
1393
        }
1394
1395 16
        return $sql . 'UNIQUE ' . $flags . '('. $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')';
1396
    }
1397
1398
    /**
1399
     * {@inheritdoc}
1400
     */
1401 33 View Code Duplication
    protected function getCreateIndexSQLFlags(Index $index)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1402
    {
1403 33
        $type = '';
1404 33
        if ($index->hasFlag('virtual')) {
1405 4
            $type .= 'VIRTUAL ';
1406
        }
1407
1408 33
        if ($index->isUnique()) {
1409 12
            $type .= 'UNIQUE ';
1410
        }
1411
1412 33
        if ($index->hasFlag('clustered')) {
1413 4
            $type .= 'CLUSTERED ';
1414
        }
1415
1416 33
        return $type;
1417
    }
1418
1419
    /**
1420
     * {@inheritdoc}
1421
     */
1422 20
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
1423
    {
1424
        return [
1425 20
            'ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)
1426
        ];
1427
    }
1428
1429
    /**
1430
     * {@inheritdoc}
1431
     */
1432 52
    protected function getReservedKeywordsClass()
1433
    {
1434 52
        return Keywords\SQLAnywhereKeywords::class;
1435
    }
1436
1437
    /**
1438
     * {@inheritdoc}
1439
     */
1440 48
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
1441
    {
1442 48
        return $fixed
1443 4
            ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')')
1444 48
            : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')');
1445
    }
1446
1447
    /**
1448
     * {@inheritdoc}
1449
     */
1450 22 View Code Duplication
    protected function initializeDoctrineTypeMappings()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1451
    {
1452 22
        $this->doctrineTypeMapping = [
1453
            'char' => 'string',
1454
            'long nvarchar' => 'text',
1455
            'long varchar' => 'text',
1456
            'nchar' => 'string',
1457
            'ntext' => 'text',
1458
            'nvarchar' => 'string',
1459
            'text' => 'text',
1460
            'uniqueidentifierstr' => 'guid',
1461
            'varchar' => 'string',
1462
            'xml' => 'text',
1463
            'bigint' => 'bigint',
1464
            'unsigned bigint' => 'bigint',
1465
            'bit' => 'boolean',
1466
            'decimal' => 'decimal',
1467
            'double' => 'float',
1468
            'float' => 'float',
1469
            'int' => 'integer',
1470
            'integer' => 'integer',
1471
            'unsigned int' => 'integer',
1472
            'numeric' => 'decimal',
1473
            'smallint' => 'smallint',
1474
            'unsigned smallint', 'smallint',
1475
            'tinyint' => 'smallint',
1476
            'unsigned tinyint', 'smallint',
1477
            'money' => 'decimal',
1478
            'smallmoney' => 'decimal',
1479
            'long varbit' => 'text',
1480
            'varbit' => 'string',
1481
            'date' => 'date',
1482
            'datetime' => 'datetime',
1483
            'smalldatetime' => 'datetime',
1484
            'time' => 'time',
1485
            'timestamp' => 'datetime',
1486
            'binary' => 'binary',
1487
            'image' => 'blob',
1488
            'long binary' => 'blob',
1489
            'uniqueidentifier' => 'guid',
1490
            'varbinary' => 'binary',
1491
        ];
1492 22
    }
1493
}
1494