Completed
Pull Request — 2.10.x (#3936)
by Asmir
61:33
created

AbstractPlatform::getPrimaryKeyColumnSQL()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 7

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 18
ccs 5
cts 5
cp 1
rs 8.8333
cc 7
nc 16
nop 1
crap 7
1
<?php
2
3
namespace Doctrine\DBAL\Platforms;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\DBAL\DBALException;
7
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
8
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
9
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
10
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
11
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
12
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
13
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
14
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
15
use Doctrine\DBAL\Events;
16
use Doctrine\DBAL\Platforms\Keywords\KeywordList;
17
use Doctrine\DBAL\Schema\Column;
18
use Doctrine\DBAL\Schema\ColumnDiff;
19
use Doctrine\DBAL\Schema\Constraint;
20
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
21
use Doctrine\DBAL\Schema\Identifier;
22
use Doctrine\DBAL\Schema\Index;
23
use Doctrine\DBAL\Schema\Sequence;
24
use Doctrine\DBAL\Schema\Table;
25
use Doctrine\DBAL\Schema\TableDiff;
26
use Doctrine\DBAL\TransactionIsolationLevel;
27
use Doctrine\DBAL\Types;
28
use Doctrine\DBAL\Types\Type;
29
use InvalidArgumentException;
30
use UnexpectedValueException;
31
use const E_USER_DEPRECATED;
32
use function addcslashes;
33
use function array_map;
34
use function array_merge;
35
use function array_unique;
36
use function array_values;
37
use function assert;
38
use function count;
39
use function explode;
40
use function func_get_arg;
41
use function func_get_args;
42
use function func_num_args;
43
use function implode;
44
use function in_array;
45
use function is_array;
46
use function is_bool;
47
use function is_int;
48
use function is_string;
49
use function preg_quote;
50
use function preg_replace;
51
use function sprintf;
52
use function str_replace;
53
use function strlen;
54
use function strpos;
55
use function strtolower;
56
use function strtoupper;
57
use function trigger_error;
58
59
/**
60
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
61
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
62
 * They are a passive source of information.
63
 *
64
 * @todo Remove any unnecessary methods.
65
 */
66
abstract class AbstractPlatform
67
{
68
    public const CREATE_INDEXES = 1;
69
70
    public const CREATE_FOREIGNKEYS = 2;
71
72
    /**
73
     * @deprecated Use DateIntervalUnit::INTERVAL_UNIT_SECOND.
74
     */
75
    public const DATE_INTERVAL_UNIT_SECOND = DateIntervalUnit::SECOND;
76
77
    /**
78
     * @deprecated Use DateIntervalUnit::MINUTE.
79
     */
80
    public const DATE_INTERVAL_UNIT_MINUTE = DateIntervalUnit::MINUTE;
81
82
    /**
83
     * @deprecated Use DateIntervalUnit::HOUR.
84
     */
85
    public const DATE_INTERVAL_UNIT_HOUR = DateIntervalUnit::HOUR;
86
87
    /**
88
     * @deprecated Use DateIntervalUnit::DAY.
89
     */
90
    public const DATE_INTERVAL_UNIT_DAY = DateIntervalUnit::DAY;
91
92
    /**
93
     * @deprecated Use DateIntervalUnit::WEEK.
94
     */
95
    public const DATE_INTERVAL_UNIT_WEEK = DateIntervalUnit::WEEK;
96
97
    /**
98
     * @deprecated Use DateIntervalUnit::MONTH.
99
     */
100
    public const DATE_INTERVAL_UNIT_MONTH = DateIntervalUnit::MONTH;
101
102
    /**
103
     * @deprecated Use DateIntervalUnit::QUARTER.
104
     */
105
    public const DATE_INTERVAL_UNIT_QUARTER = DateIntervalUnit::QUARTER;
106
107
    /**
108
     * @deprecated Use DateIntervalUnit::QUARTER.
109
     */
110
    public const DATE_INTERVAL_UNIT_YEAR = DateIntervalUnit::YEAR;
111
112
    /**
113
     * @deprecated Use TrimMode::UNSPECIFIED.
114
     */
115
    public const TRIM_UNSPECIFIED = TrimMode::UNSPECIFIED;
116
117
    /**
118
     * @deprecated Use TrimMode::LEADING.
119
     */
120
    public const TRIM_LEADING = TrimMode::LEADING;
121
122
    /**
123
     * @deprecated Use TrimMode::TRAILING.
124
     */
125
    public const TRIM_TRAILING = TrimMode::TRAILING;
126
127
    /**
128
     * @deprecated Use TrimMode::BOTH.
129
     */
130
    public const TRIM_BOTH = TrimMode::BOTH;
131
132
    /** @var string[]|null */
133
    protected $doctrineTypeMapping = null;
134
135
    /**
136
     * Contains a list of all columns that should generate parseable column comments for type-detection
137
     * in reverse engineering scenarios.
138
     *
139
     * @var string[]|null
140
     */
141
    protected $doctrineTypeComments = null;
142
143
    /** @var EventManager */
144
    protected $_eventManager;
145
146
    /**
147
     * Holds the KeywordList instance for the current platform.
148
     *
149
     * @var KeywordList|null
150
     */
151
    protected $_keywords;
152
153 67655
    /**
154
     * @param mixed[] $options
155 67655
     *
156
     * @return string
157
     */
158
    protected function getPrimaryKeyColumnSQL(array $options)
159
    {
160 60839
        $columnListSql = '';
161
        $index         = $options['primary_index'];
162 60839
        if ($index->getName() !== 'primary') {
163 60839
            $columnListSql .= 'CONSTRAINT ' . $index->getQuotedName($this) . ' ';
164
        }
165
166
        $flags = '';
167
        if (isset($options['primary_index']) && $options['primary_index']->hasFlag('nonclustered')) {
168
            $flags .= ' NONCLUSTERED';
169
        }
170 58230
171
        if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) {
172 58230
            $flags .= ' CLUSTERED';
173
        }
174
175
        return $columnListSql . 'PRIMARY KEY' . ($flags ? $flags : '') . ' (' . implode(', ', array_unique(array_values($options['primary']))) . ')';
176
    }
177
178
    public function __construct()
179
    {
180
    }
181
182
    /**
183
     * Sets the EventManager used by the Platform.
184
     *
185
     * @return void
186
     */
187
    public function setEventManager(EventManager $eventManager)
188
    {
189
        $this->_eventManager = $eventManager;
190
    }
191
192
    /**
193
     * Gets the EventManager used by the Platform.
194
     *
195
     * @return EventManager
196
     */
197
    public function getEventManager()
198
    {
199
        return $this->_eventManager;
200
    }
201
202
    /**
203
     * Returns the SQL snippet that declares a boolean column.
204
     *
205
     * @param mixed[] $columnDef
206
     *
207
     * @return string
208
     */
209
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
210
211
    /**
212
     * Returns the SQL snippet that declares a 4 byte integer column.
213
     *
214
     * @param mixed[] $columnDef
215
     *
216
     * @return string
217
     */
218
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
219
220
    /**
221
     * Returns the SQL snippet that declares an 8 byte integer column.
222
     *
223
     * @param mixed[] $columnDef
224
     *
225
     * @return string
226
     */
227
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
228
229
    /**
230
     * Returns the SQL snippet that declares a 2 byte integer column.
231
     *
232
     * @param mixed[] $columnDef
233 58308
     *
234
     * @return string
235 58308
     */
236
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
237 58308
238 58308
    /**
239 30122
     * Returns the SQL snippet that declares common properties of an integer column.
240
     *
241
     * @param mixed[] $columnDef
242 58308
     *
243
     * @return string
244
     */
245
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
246
247
    /**
248
     * Lazy load Doctrine Type Mappings.
249
     *
250
     * @return void
251 60263
     */
252
    abstract protected function initializeDoctrineTypeMappings();
253 60263
254 56812
    /**
255
     * Initializes Doctrine Type Mappings with the platform defaults
256
     * and with all additional type mappings.
257 60263
     *
258
     * @return void
259 60263
     */
260 58370
    private function initializeAllDoctrineTypeMappings()
261 60263
    {
262
        $this->initializeDoctrineTypeMappings();
263 60263
264
        foreach (Type::getTypesMap() as $typeName => $className) {
265
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
266
                $this->doctrineTypeMapping[$dbType] = $typeName;
267 60263
            }
268
        }
269
    }
270
271
    /**
272
     * Returns the SQL snippet used to declare a VARCHAR column type.
273
     *
274
     * @param mixed[] $field
275
     *
276
     * @return string
277 56993
     */
278
    public function getVarcharTypeDeclarationSQL(array $field)
279 56993
    {
280 56937
        if (! isset($field['length'])) {
281
            $field['length'] = $this->getVarcharDefaultLength();
282
        }
283 56993
284
        $fixed = $field['fixed'] ?? false;
285 56993
286
        $maxLength = $fixed
287 56993
            ? $this->getCharMaxLength()
288 54817
            : $this->getVarcharMaxLength();
289 54557
290 24
        if ($field['length'] > $maxLength) {
291 54557
            return $this->getClobTypeDeclarationSQL($field);
292 54557
        }
293 54557
294
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
295
    }
296 54817
297
    /**
298
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
299 56969
     *
300
     * @param mixed[] $field The column definition.
301
     *
302
     * @return string
303
     */
304
    public function getBinaryTypeDeclarationSQL(array $field)
305
    {
306
        if (! isset($field['length'])) {
307
            $field['length'] = $this->getBinaryDefaultLength();
308
        }
309
310
        $fixed = $field['fixed'] ?? false;
311
312 56064
        $maxLength = $this->getBinaryMaxLength();
313
314 56064
        if ($field['length'] > $maxLength) {
315 56064
            if ($maxLength > 0) {
316
                @trigger_error(sprintf(
317 56064
                    'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.',
318
                    $field['length'],
319
                    $maxLength
320
                ), E_USER_DEPRECATED);
321
            }
322
323
            return $this->getBlobTypeDeclarationSQL($field);
324
        }
325
326
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
327
    }
328
329
    /**
330 54418
     * Returns the SQL snippet to declare a GUID/UUID field.
331
     *
332 54418
     * By default this maps directly to a CHAR(36) and only maps to more
333
     * special datatypes when the underlying databases support this datatype.
334
     *
335
     * @param mixed[] $field
336
     *
337
     * @return string
338
     */
339
    public function getGuidTypeDeclarationSQL(array $field)
340
    {
341
        $field['length'] = 36;
342
        $field['fixed']  = true;
343
344
        return $this->getVarcharTypeDeclarationSQL($field);
345
    }
346
347
    /**
348
     * Returns the SQL snippet to declare a JSON field.
349
     *
350
     * By default this maps directly to a CLOB and only maps to more
351
     * special datatypes when the underlying databases support this datatype.
352
     *
353
     * @param mixed[] $field
354
     *
355
     * @return string
356
     */
357
    public function getJsonTypeDeclarationSQL(array $field)
358
    {
359
        return $this->getClobTypeDeclarationSQL($field);
360
    }
361
362
    /**
363
     * @param int  $length
364
     * @param bool $fixed
365
     *
366
     * @return string
367
     *
368
     * @throws DBALException If not supported on this platform.
369
     */
370
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
0 ignored issues
show
Unused Code introduced by
The parameter $fixed is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

370
    protected function getVarcharTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
371
    {
372
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
373
    }
374
375
    /**
376
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
377
     *
378
     * @param int  $length The length of the column.
379
     * @param bool $fixed  Whether the column length is fixed.
380
     *
381
     * @return string
382
     *
383
     * @throws DBALException If not supported on this platform.
384
     */
385
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
0 ignored issues
show
Unused Code introduced by
The parameter $fixed is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

385
    protected function getBinaryTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
386
    {
387
        throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.');
388
    }
389
390
    /**
391
     * Returns the SQL snippet used to declare a CLOB column type.
392
     *
393
     * @param mixed[] $field
394
     *
395
     * @return string
396 56422
     */
397
    abstract public function getClobTypeDeclarationSQL(array $field);
398 56422
399 55728
    /**
400
     * Returns the SQL Snippet used to declare a BLOB column type.
401
     *
402 56422
     * @param mixed[] $field
403 53971
     *
404
     * @return string
405
     */
406 56386
    abstract public function getBlobTypeDeclarationSQL(array $field);
407 56386
408
    /**
409 56386
     * Gets the name of the platform.
410
     *
411 56386
     * @return string
412 56350
     */
413
    abstract public function getName();
414
415 53948
    /**
416 53948
     * Registers a doctrine type to be used in conjunction with a column type of this platform.
417
     *
418
     * @param string $dbType
419
     * @param string $doctrineType
420
     *
421
     * @return void
422
     *
423
     * @throws DBALException If the type is not found.
424
     */
425
    public function registerDoctrineTypeMapping($dbType, $doctrineType)
426
    {
427 58342
        if ($this->doctrineTypeMapping === null) {
428
            $this->initializeAllDoctrineTypeMappings();
429 58342
        }
430 58152
431
        if (! Types\Type::hasType($doctrineType)) {
432
            throw DBALException::typeNotFound($doctrineType);
433 58342
        }
434
435 58342
        $dbType                             = strtolower($dbType);
436 54017
        $this->doctrineTypeMapping[$dbType] = $doctrineType;
437
438
        $doctrineType = Type::getType($doctrineType);
439 58306
440
        if (! $doctrineType->requiresSQLCommentHint($this)) {
441
            return;
442
        }
443
444
        $this->markDoctrineTypeCommented($doctrineType);
445
    }
446
447
    /**
448
     * Gets the Doctrine type that is mapped for the given database column type.
449 55737
     *
450
     * @param string $dbType
451 55737
     *
452 52486
     * @return string
453
     *
454
     * @throws DBALException
455 55737
     */
456
    public function getDoctrineTypeMapping($dbType)
457 55737
    {
458
        if ($this->doctrineTypeMapping === null) {
459
            $this->initializeAllDoctrineTypeMappings();
460
        }
461
462
        $dbType = strtolower($dbType);
463
464
        if (! isset($this->doctrineTypeMapping[$dbType])) {
465 61739
            throw new DBALException('Unknown database type ' . $dbType . ' requested, ' . static::class . ' may not support it.');
466
        }
467 61739
468
        return $this->doctrineTypeMapping[$dbType];
469 61739
    }
470 61739
471
    /**
472 61739
     * Checks if a database type is currently supported by this platform.
473 61739
     *
474
     * @param string $dbType
475
     *
476 61739
     * @return bool
477
     */
478 61739
    public function hasDoctrineTypeMappingFor($dbType)
479
    {
480
        if ($this->doctrineTypeMapping === null) {
481
            $this->initializeAllDoctrineTypeMappings();
482
        }
483
484
        $dbType = strtolower($dbType);
485 62005
486
        return isset($this->doctrineTypeMapping[$dbType]);
487 62005
    }
488 61703
489
    /**
490
     * Initializes the Doctrine Type comments instance variable for in_array() checks.
491 62005
     *
492
     * @return void
493 62005
     */
494
    protected function initializeCommentedDoctrineTypes()
495
    {
496
        $this->doctrineTypeComments = [];
497
498
        foreach (Type::getTypesMap() as $typeName => $className) {
499
            $type = Type::getType($typeName);
500
501
            if (! $type->requiresSQLCommentHint($this)) {
502
                continue;
503 53948
            }
504
505 53948
            $this->doctrineTypeComments[] = $typeName;
506 53948
        }
507
    }
508
509 53948
    /**
510
     * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type?
511 53948
     *
512 53948
     * @return bool
513
     */
514
    public function isCommentedDoctrineType(Type $doctrineType)
515
    {
516
        if ($this->doctrineTypeComments === null) {
517
            $this->initializeCommentedDoctrineTypes();
518
        }
519 57478
520
        assert(is_array($this->doctrineTypeComments));
521 57478
522
        return in_array($doctrineType->getName(), $this->doctrineTypeComments);
523
    }
524
525
    /**
526
     * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements.
527
     *
528
     * @param string|Type $doctrineType
529 61071
     *
530
     * @return void
531 61071
     */
532
    public function markDoctrineTypeCommented($doctrineType)
533 61071
    {
534 57478
        if ($this->doctrineTypeComments === null) {
535
            $this->initializeCommentedDoctrineTypes();
536
        }
537 61071
538
        assert(is_array($this->doctrineTypeComments));
539
540
        $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
541
    }
542
543
    /**
544
     * Gets the comment to append to a column comment that helps parsing this type in reverse engineering.
545 56981
     *
546
     * @return string
547 56981
     */
548
    public function getDoctrineTypeComment(Type $doctrineType)
549
    {
550
        return '(DC2Type:' . $doctrineType->getName() . ')';
551
    }
552
553
    /**
554
     * Gets the comment of a passed column modified by potential doctrine type comment hints.
555
     *
556
     * @return string|null
557
     */
558
    protected function getColumnComment(Column $column)
559
    {
560
        $comment = $column->getComment();
561
562
        if ($this->isCommentedDoctrineType($column->getType())) {
563
            $comment .= $this->getDoctrineTypeComment($column->getType());
564
        }
565
566
        return $comment;
567
    }
568
569
    /**
570
     * Gets the character used for identifier quoting.
571
     *
572
     * @return string
573 58124
     */
574
    public function getIdentifierQuoteCharacter()
575 58124
    {
576
        return '"';
577
    }
578
579
    /**
580
     * Gets the string portion that starts an SQL comment.
581
     *
582
     * @return string
583 55849
     */
584
    public function getSqlCommentStartString()
585 55849
    {
586
        return '--';
587
    }
588
589
    /**
590
     * Gets the string portion that ends an SQL comment.
591
     *
592
     * @return string
593 56788
     */
594
    public function getSqlCommentEndString()
595 56788
    {
596
        return "\n";
597
    }
598
599
    /**
600
     * Gets the maximum length of a char field.
601
     */
602
    public function getCharMaxLength() : int
603
    {
604
        return $this->getVarcharMaxLength();
605
    }
606
607
    /**
608
     * Gets the maximum length of a varchar field.
609
     *
610
     * @return int
611
     */
612
    public function getVarcharMaxLength()
613 54802
    {
614
        return 4000;
615 54802
    }
616
617
    /**
618
     * Gets the default length of a varchar field.
619
     *
620
     * @return int
621
     */
622
    public function getVarcharDefaultLength()
623
    {
624
        return 255;
625
    }
626
627
    /**
628
     * Gets the maximum length of a binary field.
629
     *
630
     * @return int
631
     */
632
    public function getBinaryMaxLength()
633
    {
634
        return 4000;
635 44078
    }
636
637 44078
    /**
638
     * Gets the default length of a binary field.
639
     *
640
     * @return int
641
     */
642
    public function getBinaryDefaultLength()
643
    {
644
        return 255;
645
    }
646
647
    /**
648
     * Gets all SQL wildcard characters of the platform.
649
     *
650
     * @return string[]
651
     */
652
    public function getWildcards()
653
    {
654
        return ['%', '_'];
655
    }
656
657
    /**
658
     * Returns the regular expression operator.
659
     *
660
     * @return string
661
     *
662
     * @throws DBALException If not supported on this platform.
663
     */
664
    public function getRegexpExpression()
665
    {
666
        throw DBALException::notSupported(__METHOD__);
667
    }
668
669
    /**
670
     * Returns the global unique identifier expression.
671
     *
672
     * @deprecated Use application-generated UUIDs instead
673
     *
674
     * @return string
675
     *
676
     * @throws DBALException If not supported on this platform.
677
     */
678
    public function getGuidExpression()
679
    {
680
        throw DBALException::notSupported(__METHOD__);
681
    }
682
683
    /**
684
     * Returns the SQL snippet to get the average value of a column.
685
     *
686
     * @param string $column The column to use.
687
     *
688
     * @return string Generated SQL including an AVG aggregate function.
689
     */
690
    public function getAvgExpression($column)
691
    {
692
        return 'AVG(' . $column . ')';
693
    }
694
695
    /**
696
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
697
     *
698
     * If a '*' is used instead of a column the number of selected rows is returned.
699
     *
700
     * @param string|int $column The column to use.
701
     *
702
     * @return string Generated SQL including a COUNT aggregate function.
703
     */
704
    public function getCountExpression($column)
705
    {
706
        return 'COUNT(' . $column . ')';
707
    }
708
709
    /**
710
     * Returns the SQL snippet to get the highest value of a column.
711
     *
712
     * @param string $column The column to use.
713
     *
714
     * @return string Generated SQL including a MAX aggregate function.
715
     */
716
    public function getMaxExpression($column)
717
    {
718
        return 'MAX(' . $column . ')';
719
    }
720
721
    /**
722
     * Returns the SQL snippet to get the lowest value of a column.
723
     *
724
     * @param string $column The column to use.
725
     *
726
     * @return string Generated SQL including a MIN aggregate function.
727
     */
728
    public function getMinExpression($column)
729
    {
730
        return 'MIN(' . $column . ')';
731
    }
732
733
    /**
734
     * Returns the SQL snippet to get the total sum of a column.
735
     *
736
     * @param string $column The column to use.
737
     *
738
     * @return string Generated SQL including a SUM aggregate function.
739
     */
740
    public function getSumExpression($column)
741
    {
742
        return 'SUM(' . $column . ')';
743
    }
744
745
    // scalar functions
746
747
    /**
748
     * Returns the SQL snippet to get the md5 sum of a field.
749
     *
750
     * Note: Not SQL92, but common functionality.
751
     *
752
     * @param string $column
753
     *
754
     * @return string
755
     */
756
    public function getMd5Expression($column)
757
    {
758
        return 'MD5(' . $column . ')';
759
    }
760
761
    /**
762
     * Returns the SQL snippet to get the length of a text field.
763
     *
764
     * @param string $column
765
     *
766
     * @return string
767
     */
768
    public function getLengthExpression($column)
769
    {
770
        return 'LENGTH(' . $column . ')';
771
    }
772
773
    /**
774
     * Returns the SQL snippet to get the squared value of a column.
775
     *
776
     * @param string $column The column to use.
777
     *
778
     * @return string Generated SQL including an SQRT aggregate function.
779
     */
780
    public function getSqrtExpression($column)
781
    {
782
        return 'SQRT(' . $column . ')';
783
    }
784
785
    /**
786
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
787
     *
788
     * @param string $column
789
     * @param int    $decimals
790
     *
791 51813
     * @return string
792
     */
793 51813
    public function getRoundExpression($column, $decimals = 0)
794
    {
795 51813
        return 'ROUND(' . $column . ', ' . $decimals . ')';
796
    }
797 51739
798 51739
    /**
799
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
800
     *
801 51719
     * @param string $expression1
802 51719
     * @param string $expression2
803
     *
804
     * @return string
805 51699
     */
806 51699
    public function getModExpression($expression1, $expression2)
807
    {
808
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
809 51813
    }
810 51717
811
    /**
812
     * Returns the SQL snippet to trim a string.
813 51813
     *
814 51789
     * @param string      $str  The expression to apply the trim to.
815
     * @param int         $mode The position of the trim (leading/trailing/both).
816
     * @param string|bool $char The char to trim, has to be quoted already. Defaults to space.
817 51813
     *
818
     * @return string
819
     */
820
    public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false)
821
    {
822
        $expression = '';
823
824
        switch ($mode) {
825
            case TrimMode::LEADING:
826
                $expression = 'LEADING ';
827 25975
                break;
828
829 25975
            case TrimMode::TRAILING:
830
                $expression = 'TRAILING ';
831
                break;
832
833
            case TrimMode::BOTH:
834
                $expression = 'BOTH ';
835
                break;
836
        }
837
838
        if ($char !== false) {
839 25975
            $expression .= $char . ' ';
0 ignored issues
show
Bug introduced by
Are you sure $char of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

839
            $expression .= /** @scrutinizer ignore-type */ $char . ' ';
Loading history...
840
        }
841 25975
842
        if ($mode || $char !== false) {
843
            $expression .= 'FROM ';
844
        }
845
846
        return 'TRIM(' . $expression . $str . ')';
847
    }
848
849
    /**
850
     * Returns the SQL snippet to trim trailing space characters from the expression.
851
     *
852
     * @param string $str Literal string or column name.
853
     *
854
     * @return string
855
     */
856
    public function getRtrimExpression($str)
857
    {
858
        return 'RTRIM(' . $str . ')';
859
    }
860
861
    /**
862
     * Returns the SQL snippet to trim leading space characters from the expression.
863
     *
864
     * @param string $str Literal string or column name.
865
     *
866
     * @return string
867
     */
868
    public function getLtrimExpression($str)
869
    {
870
        return 'LTRIM(' . $str . ')';
871
    }
872
873
    /**
874
     * Returns the SQL snippet to change all characters from the expression to uppercase,
875
     * according to the current character set mapping.
876
     *
877
     * @param string $str Literal string or column name.
878
     *
879
     * @return string
880
     */
881
    public function getUpperExpression($str)
882
    {
883
        return 'UPPER(' . $str . ')';
884
    }
885
886
    /**
887
     * Returns the SQL snippet to change all characters from the expression to lowercase,
888
     * according to the current character set mapping.
889
     *
890
     * @param string $str Literal string or column name.
891
     *
892
     * @return string
893
     */
894
    public function getLowerExpression($str)
895
    {
896
        return 'LOWER(' . $str . ')';
897
    }
898
899
    /**
900
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
901
     *
902
     * @param string    $str      Literal string.
903
     * @param string    $substr   Literal string to find.
904
     * @param int|false $startPos Position to start at, beginning of string by default.
905
     *
906
     * @return string
907
     *
908
     * @throws DBALException If not supported on this platform.
909
     */
910
    public function getLocateExpression($str, $substr, $startPos = false)
0 ignored issues
show
Unused Code introduced by
The parameter $startPos is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

910
    public function getLocateExpression($str, $substr, /** @scrutinizer ignore-unused */ $startPos = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $substr is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

910
    public function getLocateExpression($str, /** @scrutinizer ignore-unused */ $substr, $startPos = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
911
    {
912
        throw DBALException::notSupported(__METHOD__);
913
    }
914
915
    /**
916
     * Returns the SQL snippet to get the current system date.
917
     *
918
     * @return string
919
     */
920
    public function getNowExpression()
921
    {
922
        return 'NOW()';
923
    }
924
925 44057
    /**
926
     * Returns a SQL snippet to get a substring inside an SQL statement.
927 44057
     *
928
     * Note: Not SQL92, but common functionality.
929
     *
930
     * SQLite only supports the 2 parameter variant of this function.
931
     *
932
     * @param string   $value  An sql string literal or column name/alias.
933
     * @param int      $from   Where to start the substring portion.
934
     * @param int|null $length The substring portion length.
935
     *
936
     * @return string
937
     */
938
    public function getSubstringExpression($value, $from, $length = null)
939
    {
940
        if ($length === null) {
941
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
942
        }
943
944
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
945
    }
946
947
    /**
948
     * Returns a SQL snippet to concatenate the given expressions.
949
     *
950
     * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
951
     *
952
     * @return string
953
     */
954
    public function getConcatExpression()
955
    {
956
        return implode(' || ', func_get_args());
957 60723
    }
958
959 60723
    /**
960
     * Returns the SQL for a logical not.
961
     *
962
     * Example:
963
     * <code>
964
     * $q = new Doctrine_Query();
965
     * $e = $q->expr;
966
     * $q->select('*')->from('table')
967
     *   ->where($e->eq('id', $e->not('null'));
968
     * </code>
969
     *
970
     * @param string $expression
971
     *
972
     * @return string The logical expression.
973
     */
974
    public function getNotExpression($expression)
975
    {
976
        return 'NOT(' . $expression . ')';
977
    }
978
979
    /**
980
     * Returns the SQL that checks if an expression is null.
981
     *
982
     * @param string $expression The expression that should be compared to null.
983
     *
984
     * @return string The logical expression.
985
     */
986
    public function getIsNullExpression($expression)
987
    {
988
        return $expression . ' IS NULL';
989
    }
990
991
    /**
992
     * Returns the SQL that checks if an expression is not null.
993
     *
994
     * @param string $expression The expression that should be compared to null.
995
     *
996
     * @return string The logical expression.
997
     */
998
    public function getIsNotNullExpression($expression)
999
    {
1000
        return $expression . ' IS NOT NULL';
1001
    }
1002
1003
    /**
1004
     * Returns the SQL that checks if an expression evaluates to a value between two values.
1005
     *
1006
     * The parameter $expression is checked if it is between $value1 and $value2.
1007
     *
1008
     * Note: There is a slight difference in the way BETWEEN works on some databases.
1009
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
1010
     * independence you should avoid using between().
1011
     *
1012
     * @param string $expression The value to compare to.
1013
     * @param string $value1     The lower value to compare with.
1014
     * @param string $value2     The higher value to compare with.
1015
     *
1016
     * @return string The logical expression.
1017
     */
1018
    public function getBetweenExpression($expression, $value1, $value2)
1019
    {
1020
        return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2;
1021
    }
1022
1023
    /**
1024
     * Returns the SQL to get the arccosine of a value.
1025
     *
1026
     * @param string $value
1027
     *
1028
     * @return string
1029
     */
1030
    public function getAcosExpression($value)
1031
    {
1032
        return 'ACOS(' . $value . ')';
1033
    }
1034
1035
    /**
1036
     * Returns the SQL to get the sine of a value.
1037
     *
1038
     * @param string $value
1039
     *
1040
     * @return string
1041
     */
1042
    public function getSinExpression($value)
1043
    {
1044
        return 'SIN(' . $value . ')';
1045
    }
1046
1047
    /**
1048
     * Returns the SQL to get the PI value.
1049
     *
1050
     * @return string
1051
     */
1052
    public function getPiExpression()
1053
    {
1054
        return 'PI()';
1055
    }
1056
1057
    /**
1058
     * Returns the SQL to get the cosine of a value.
1059
     *
1060
     * @param string $value
1061
     *
1062
     * @return string
1063
     */
1064
    public function getCosExpression($value)
1065
    {
1066
        return 'COS(' . $value . ')';
1067 59060
    }
1068
1069 59060
    /**
1070
     * Returns the SQL to calculate the difference in days between the two passed dates.
1071
     *
1072
     * Computes diff = date1 - date2.
1073
     *
1074
     * @param string $date1
1075
     * @param string $date2
1076
     *
1077
     * @return string
1078
     *
1079
     * @throws DBALException If not supported on this platform.
1080
     */
1081
    public function getDateDiffExpression($date1, $date2)
0 ignored issues
show
Unused Code introduced by
The parameter $date1 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1081
    public function getDateDiffExpression(/** @scrutinizer ignore-unused */ $date1, $date2)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $date2 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1081
    public function getDateDiffExpression($date1, /** @scrutinizer ignore-unused */ $date2)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1082 59060
    {
1083
        throw DBALException::notSupported(__METHOD__);
1084 59060
    }
1085
1086
    /**
1087
     * Returns the SQL to add the number of given seconds to a date.
1088
     *
1089
     * @param string $date
1090
     * @param int    $seconds
1091
     *
1092
     * @return string
1093
     *
1094
     * @throws DBALException If not supported on this platform.
1095
     */
1096
    public function getDateAddSecondsExpression($date, $seconds)
1097 59060
    {
1098
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND);
1099 59060
    }
1100
1101
    /**
1102
     * Returns the SQL to subtract the number of given seconds from a date.
1103
     *
1104
     * @param string $date
1105
     * @param int    $seconds
1106
     *
1107
     * @return string
1108
     *
1109
     * @throws DBALException If not supported on this platform.
1110
     */
1111
    public function getDateSubSecondsExpression($date, $seconds)
1112 59060
    {
1113
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND);
1114 59060
    }
1115
1116
    /**
1117
     * Returns the SQL to add the number of given minutes to a date.
1118
     *
1119
     * @param string $date
1120
     * @param int    $minutes
1121
     *
1122
     * @return string
1123
     *
1124
     * @throws DBALException If not supported on this platform.
1125
     */
1126
    public function getDateAddMinutesExpression($date, $minutes)
1127 59060
    {
1128
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE);
1129 59060
    }
1130
1131
    /**
1132
     * Returns the SQL to subtract the number of given minutes from a date.
1133
     *
1134
     * @param string $date
1135
     * @param int    $minutes
1136
     *
1137
     * @return string
1138
     *
1139
     * @throws DBALException If not supported on this platform.
1140
     */
1141
    public function getDateSubMinutesExpression($date, $minutes)
1142 59060
    {
1143
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE);
1144 59060
    }
1145
1146
    /**
1147
     * Returns the SQL to add the number of given hours to a date.
1148
     *
1149
     * @param string $date
1150
     * @param int    $hours
1151
     *
1152
     * @return string
1153
     *
1154
     * @throws DBALException If not supported on this platform.
1155
     */
1156
    public function getDateAddHourExpression($date, $hours)
1157 59064
    {
1158
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR);
1159 59064
    }
1160
1161
    /**
1162
     * Returns the SQL to subtract the number of given hours to a date.
1163
     *
1164
     * @param string $date
1165
     * @param int    $hours
1166
     *
1167
     * @return string
1168
     *
1169
     * @throws DBALException If not supported on this platform.
1170
     */
1171
    public function getDateSubHourExpression($date, $hours)
1172 59060
    {
1173
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR);
1174 59060
    }
1175
1176
    /**
1177
     * Returns the SQL to add the number of given days to a date.
1178
     *
1179
     * @param string $date
1180
     * @param int    $days
1181
     *
1182
     * @return string
1183
     *
1184
     * @throws DBALException If not supported on this platform.
1185
     */
1186
    public function getDateAddDaysExpression($date, $days)
1187 59060
    {
1188
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY);
1189 59060
    }
1190
1191
    /**
1192
     * Returns the SQL to subtract the number of given days to a date.
1193
     *
1194
     * @param string $date
1195
     * @param int    $days
1196
     *
1197
     * @return string
1198
     *
1199
     * @throws DBALException If not supported on this platform.
1200
     */
1201
    public function getDateSubDaysExpression($date, $days)
1202 59060
    {
1203
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY);
1204 59060
    }
1205
1206
    /**
1207
     * Returns the SQL to add the number of given weeks to a date.
1208
     *
1209
     * @param string $date
1210
     * @param int    $weeks
1211
     *
1212
     * @return string
1213
     *
1214
     * @throws DBALException If not supported on this platform.
1215
     */
1216
    public function getDateAddWeeksExpression($date, $weeks)
1217 59060
    {
1218
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK);
1219 59060
    }
1220
1221
    /**
1222
     * Returns the SQL to subtract the number of given weeks from a date.
1223
     *
1224
     * @param string $date
1225
     * @param int    $weeks
1226
     *
1227
     * @return string
1228
     *
1229
     * @throws DBALException If not supported on this platform.
1230
     */
1231
    public function getDateSubWeeksExpression($date, $weeks)
1232 59060
    {
1233
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK);
1234 59060
    }
1235
1236
    /**
1237
     * Returns the SQL to add the number of given months to a date.
1238
     *
1239
     * @param string $date
1240
     * @param int    $months
1241
     *
1242
     * @return string
1243
     *
1244
     * @throws DBALException If not supported on this platform.
1245
     */
1246
    public function getDateAddMonthExpression($date, $months)
1247 59060
    {
1248
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH);
1249 59060
    }
1250
1251
    /**
1252
     * Returns the SQL to subtract the number of given months to a date.
1253
     *
1254
     * @param string $date
1255
     * @param int    $months
1256
     *
1257
     * @return string
1258
     *
1259
     * @throws DBALException If not supported on this platform.
1260
     */
1261
    public function getDateSubMonthExpression($date, $months)
1262 59060
    {
1263
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH);
1264 59060
    }
1265
1266
    /**
1267
     * Returns the SQL to add the number of given quarters to a date.
1268
     *
1269
     * @param string $date
1270
     * @param int    $quarters
1271
     *
1272
     * @return string
1273
     *
1274
     * @throws DBALException If not supported on this platform.
1275
     */
1276
    public function getDateAddQuartersExpression($date, $quarters)
1277 59060
    {
1278
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER);
1279 59060
    }
1280
1281
    /**
1282
     * Returns the SQL to subtract the number of given quarters from a date.
1283
     *
1284
     * @param string $date
1285
     * @param int    $quarters
1286
     *
1287
     * @return string
1288
     *
1289
     * @throws DBALException If not supported on this platform.
1290
     */
1291
    public function getDateSubQuartersExpression($date, $quarters)
1292 59060
    {
1293
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER);
1294 59060
    }
1295
1296
    /**
1297
     * Returns the SQL to add the number of given years to a date.
1298
     *
1299
     * @param string $date
1300
     * @param int    $years
1301
     *
1302
     * @return string
1303
     *
1304
     * @throws DBALException If not supported on this platform.
1305
     */
1306
    public function getDateAddYearsExpression($date, $years)
1307
    {
1308
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR);
1309
    }
1310
1311
    /**
1312
     * Returns the SQL to subtract the number of given years from a date.
1313
     *
1314
     * @param string $date
1315
     * @param int    $years
1316
     *
1317
     * @return string
1318
     *
1319
     * @throws DBALException If not supported on this platform.
1320
     */
1321
    public function getDateSubYearsExpression($date, $years)
1322
    {
1323 58745
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR);
1324
    }
1325 58745
1326
    /**
1327
     * Returns the SQL for a date arithmetic expression.
1328
     *
1329
     * @param string $date     The column or literal representing a date to perform the arithmetic operation on.
1330
     * @param string $operator The arithmetic operator (+ or -).
1331
     * @param int    $interval The interval that shall be calculated into the date.
1332
     * @param string $unit     The unit of the interval that shall be calculated into the date.
1333
     *                         One of the DATE_INTERVAL_UNIT_* constants.
1334
     *
1335
     * @return string
1336 56530
     *
1337
     * @throws DBALException If not supported on this platform.
1338 56530
     */
1339
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
0 ignored issues
show
Unused Code introduced by
The parameter $unit is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1339
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, /** @scrutinizer ignore-unused */ $unit)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1339
    protected function getDateArithmeticIntervalExpression($date, /** @scrutinizer ignore-unused */ $operator, $interval, $unit)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $interval is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1339
    protected function getDateArithmeticIntervalExpression($date, $operator, /** @scrutinizer ignore-unused */ $interval, $unit)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1340
    {
1341
        throw DBALException::notSupported(__METHOD__);
1342
    }
1343
1344
    /**
1345
     * Returns the SQL bit AND comparison expression.
1346 46030
     *
1347
     * @param string $value1
1348 46030
     * @param string $value2
1349
     *
1350
     * @return string
1351
     */
1352
    public function getBitAndComparisonExpression($value1, $value2)
1353
    {
1354
        return '(' . $value1 . ' & ' . $value2 . ')';
1355
    }
1356
1357
    /**
1358
     * Returns the SQL bit OR comparison expression.
1359
     *
1360 48452
     * @param string $value1
1361
     * @param string $value2
1362 48452
     *
1363
     * @return string
1364
     */
1365
    public function getBitOrComparisonExpression($value1, $value2)
1366
    {
1367
        return '(' . $value1 . ' | ' . $value2 . ')';
1368
    }
1369
1370
    /**
1371
     * Returns the FOR UPDATE expression.
1372
     *
1373
     * @return string
1374
     */
1375
    public function getForUpdateSQL()
1376
    {
1377
        return 'FOR UPDATE';
1378
    }
1379
1380
    /**
1381
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1382
     *
1383
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1384
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1385 53298
     *                             be appended to the FROM clause.
1386
     *
1387 53298
     * @return string
1388
     */
1389
    public function appendLockHint($fromClause, $lockMode)
0 ignored issues
show
Unused Code introduced by
The parameter $lockMode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1389
    public function appendLockHint($fromClause, /** @scrutinizer ignore-unused */ $lockMode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1390
    {
1391
        return $fromClause;
1392
    }
1393
1394
    /**
1395
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1396
     *
1397 47094
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1398
     * vendors allow to lighten this constraint up to be a real read lock.
1399 47094
     *
1400
     * @return string
1401
     */
1402
    public function getReadLockSQL()
1403
    {
1404
        return $this->getForUpdateSQL();
1405
    }
1406
1407
    /**
1408
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1409
     *
1410
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1411 60247
     *
1412
     * @return string
1413 60247
     */
1414
    public function getWriteLockSQL()
1415 60247
    {
1416 6785
        return $this->getForUpdateSQL();
1417
    }
1418
1419 60247
    /**
1420
     * Returns the SQL snippet to drop an existing database.
1421
     *
1422
     * @param string $database The name of the database that should be dropped.
1423 60247
     *
1424 53580
     * @return string
1425 53580
     */
1426
    public function getDropDatabaseSQL($database)
1427 53580
    {
1428
        return 'DROP DATABASE ' . $database;
1429
    }
1430
1431
    /**
1432
     * Returns the SQL snippet to drop an existing table.
1433
     *
1434
     * @param Table|string $table
1435
     *
1436
     * @return string
1437
     *
1438 60247
     * @throws InvalidArgumentException
1439
     */
1440
    public function getDropTableSQL($table)
1441
    {
1442
        $tableArg = $table;
1443
1444
        if ($table instanceof Table) {
1445
            $table = $table->getQuotedName($this);
1446
        }
1447
1448 26635
        if (! is_string($table)) {
0 ignored issues
show
introduced by
The condition is_string($table) is always true.
Loading history...
1449
            throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1450 26635
        }
1451
1452
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1453
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1454
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1455
1456
            if ($eventArgs->isDefaultPrevented()) {
1457
                $sql = $eventArgs->getSql();
1458
1459
                if ($sql === null) {
1460
                    throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL');
1461
                }
1462
1463 47006
                return $sql;
1464
            }
1465 47006
        }
1466 46977
1467 22332
        return 'DROP TABLE ' . $table;
1468
    }
1469
1470
    /**
1471 47006
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1472
     *
1473
     * @param Table|string $table
1474
     *
1475
     * @return string
1476
     */
1477
    public function getDropTemporaryTableSQL($table)
1478
    {
1479
        return $this->getDropTableSQL($table);
1480
    }
1481
1482 54399
    /**
1483
     * Returns the SQL to drop an index from a table.
1484 54399
     *
1485 53144
     * @param Index|string $index
1486
     * @param Table|string $table
1487
     *
1488 54399
     * @return string
1489 54399
     *
1490
     * @throws InvalidArgumentException
1491
     */
1492 54399
    public function getDropIndexSQL($index, $table = null)
1493 54399
    {
1494
        $isPrimary = false;
1495 54399
        if ($index instanceof Index) {
1496
            $isPrimary = $index->isPrimary();
1497
            $index     = $index->getQuotedName($this);
1498
        } elseif (! is_string($index)) {
0 ignored issues
show
introduced by
The condition is_string($index) is always true.
Loading history...
1499
            throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1500
        }
1501
1502
        if ($isPrimary && $table !== null && $this->supportsNamedPrimaryConstraints()) {
1503
            $tableName = $table instanceof Table ? $table->getQuotedName($this) : $table;
1504
1505
            return 'ALTER TABLE ' . $tableName . ' DROP CONSTRAINT ' . $index;
1506 55174
        }
1507
1508 55174
        return 'DROP INDEX ' . $index;
1509 52893
    }
1510
1511
    /**
1512 55174
     * Returns the SQL to drop a constraint.
1513 55174
     *
1514
     * @param Constraint|string $constraint
1515
     * @param Table|string      $table
1516 55174
     *
1517 55174
     * @return string
1518
     */
1519 55174
    public function getDropConstraintSQL($constraint, $table)
1520
    {
1521
        if (! $constraint instanceof Constraint) {
1522
            $constraint = new Identifier($constraint);
1523
        }
1524
1525
        if (! $table instanceof Table) {
1526
            $table = new Identifier($table);
1527
        }
1528
1529
        $constraint = $constraint->getQuotedName($this);
1530
        $table      = $table->getQuotedName($this);
1531
1532
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1533 60785
    }
1534
1535 60785
    /**
1536
     * Returns the SQL to drop a foreign key.
1537
     *
1538
     * @param ForeignKeyConstraint|string $foreignKey
1539 60785
     * @param Table|string                $table
1540 53856
     *
1541
     * @return string
1542
     */
1543 60749
    public function getDropForeignKeySQL($foreignKey, $table)
1544 60749
    {
1545 60749
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1546 60749
            $foreignKey = new Identifier($foreignKey);
1547 60749
        }
1548
1549 60749
        if (! $table instanceof Table) {
1550 60703
            $table = new Identifier($table);
1551
        }
1552 60443
1553 60311
        $foreignKey = $foreignKey->getQuotedName($this);
1554 60311
        $table      = $table->getQuotedName($this);
1555
1556 58982
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1557
    }
1558
1559
    /**
1560
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1561 60749
     * on this platform.
1562 60749
     *
1563
     * @param int $createFlags
1564 60749
     *
1565 60749
     * @return string[] The sequence of SQL statements.
1566 53603
     *
1567 53603
     * @throws DBALException
1568
     * @throws InvalidArgumentException
1569 53603
     */
1570
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1571 53603
    {
1572
        if (! is_int($createFlags)) {
0 ignored issues
show
introduced by
The condition is_int($createFlags) is always true.
Loading history...
1573
            throw new InvalidArgumentException('Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.');
1574
        }
1575
1576 60749
        if (count($table->getColumns()) === 0) {
1577 60749
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1578 60749
        }
1579 60749
1580
        $tableName                    = $table->getQuotedName($this);
1581 60749
        $options                      = $table->getOptions();
1582 59881
        $options['uniqueConstraints'] = [];
1583
        $options['indexes']           = [];
1584
        $options['primary']           = [];
1585 60749
1586 60271
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1587
            foreach ($table->getIndexes() as $index) {
1588
                /** @var $index Index */
1589 60749
                if ($index->isPrimary()) {
1590
                    $options['primary']       = $index->getQuotedColumns($this);
1591
                    $options['primary_index'] = $index;
1592 60749
                } else {
1593 60295
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1594 60295
                }
1595 58801
            }
1596
        }
1597
1598
        $columnSql = [];
1599 60749
        $columns   = [];
1600 53603
1601 53603
        foreach ($table->getColumns() as $column) {
1602
            if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) {
1603 53603
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1604
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1605
1606
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1607
1608 60749
                if ($eventArgs->isDefaultPrevented()) {
1609 60749
                    continue;
1610 57196
                }
1611 38867
            }
1612
1613 57196
            $columnData            = $column->toArray();
1614 57196
            $columnData['name']    = $column->getQuotedName($this);
1615
            $columnData['version'] = $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false;
1616 57196
            $columnData['comment'] = $this->getColumnComment($column);
1617 57162
1618
            if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) {
1619
                $columnData['length'] = 255;
1620 54948
            }
1621
1622
            if (in_array($column->getName(), $options['primary'])) {
1623
                $columnData['primary'] = true;
1624 60749
            }
1625
1626
            $columns[$columnData['name']] = $columnData;
1627 38867
        }
1628
1629 38867
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1630
            $options['foreignKeys'] = [];
1631 38867
            foreach ($table->getForeignKeys() as $fkConstraint) {
1632 4
                $options['foreignKeys'][] = $fkConstraint;
1633 38867
            }
1634 38867
        }
1635
1636
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
1637
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1638
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1639
1640
            if ($eventArgs->isDefaultPrevented()) {
1641
                return array_merge($eventArgs->getSql(), $columnSql);
1642
            }
1643
        }
1644
1645 53797
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1646
        if ($this->supportsCommentOnStatement()) {
1647 53797
            if ($table->hasOption('comment')) {
1648 53797
                $sql[] = $this->getCommentOnTableSQL($tableName, $table->getOption('comment'));
1649
            }
1650 53797
            foreach ($table->getColumns() as $column) {
1651 132
                $comment = $this->getColumnComment($column);
1652 53797
1653 53797
                if ($comment === null || $comment === '') {
1654 53797
                    continue;
1655
                }
1656
1657
                $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1658
            }
1659
        }
1660
1661
        return array_merge($sql, $columnSql);
1662
    }
1663
1664
    protected function getCommentOnTableSQL(string $tableName, ?string $comment) : string
1665
    {
1666
        $tableName = new Identifier($tableName);
1667 55298
1668
        return sprintf(
1669 55298
            'COMMENT ON TABLE %s IS %s',
1670 52790
            $tableName->getQuotedName($this),
1671
            $this->quoteStringLiteral((string) $comment)
1672
        );
1673 54335
    }
1674
1675
    /**
1676
     * @param string      $tableName
1677
     * @param string      $columnName
1678
     * @param string|null $comment
1679
     *
1680
     * @return string
1681
     */
1682
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
1683
    {
1684
        $tableName  = new Identifier($tableName);
1685 55330
        $columnName = new Identifier($columnName);
1686
1687 55330
        return sprintf(
1688
            'COMMENT ON COLUMN %s.%s IS %s',
1689 55330
            $tableName->getQuotedName($this),
1690
            $columnName->getQuotedName($this),
1691
            $this->quoteStringLiteral((string) $comment)
1692
        );
1693
    }
1694
1695 55330
    /**
1696 55198
     * Returns the SQL to create inline comment on a column.
1697
     *
1698
     * @param string $comment
1699 55330
     *
1700
     * @return string
1701
     *
1702
     * @throws DBALException If not supported on this platform.
1703
     */
1704
    public function getInlineColumnCommentSQL($comment)
1705 55330
    {
1706
        if (! $this->supportsInlineColumnComments()) {
1707 55330
            throw DBALException::notSupported(__METHOD__);
1708 55330
        }
1709 54765
1710
        return 'COMMENT ' . $this->quoteStringLiteral($comment);
1711 55330
    }
1712
1713 55330
    /**
1714
     * Returns the SQL used to create a table.
1715 55330
     *
1716 55250
     * @param string    $tableName
1717 54911
     * @param mixed[][] $columns
1718
     * @param mixed[]   $options
1719
     *
1720
     * @return string[]
1721 55330
     */
1722
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1723
    {
1724
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1725
1726
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1727 48409
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1728
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1729 48409
            }
1730
        }
1731
1732
        if (isset($options['primary']) && ! empty($options['primary'])) {
1733
            $columnListSql .= ', ' . $this->getPrimaryKeyColumnSQL($options);
1734
        }
1735
1736
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1737
            foreach ($options['indexes'] as $index => $definition) {
1738
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1739
            }
1740
        }
1741
1742
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1743
1744
        $check = $this->getCheckDeclarationSQL($columns);
1745
        if (! empty($check)) {
1746
            $query .= ', ' . $check;
1747
        }
1748
        $query .= ')';
1749
1750
        $sql[] = $query;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.
Loading history...
1751
1752
        if (isset($options['foreignKeys'])) {
1753
            foreach ((array) $options['foreignKeys'] as $definition) {
1754
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1755
            }
1756
        }
1757
1758
        return $sql;
1759
    }
1760
1761
    /**
1762
     * @return string
1763
     */
1764
    public function getCreateTemporaryTableSnippetSQL()
1765 53762
    {
1766
        return 'CREATE TEMPORARY TABLE';
1767 53762
    }
1768
1769
    /**
1770
     * Returns the SQL to create a sequence on this platform.
1771 53762
     *
1772
     * @return string
1773 53762
     *
1774
     * @throws DBALException If not supported on this platform.
1775 53762
     */
1776 53762
    public function getCreateSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1776
    public function getCreateSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1777 53762
    {
1778 53762
        throw DBALException::notSupported(__METHOD__);
1779 53708
    }
1780 53708
1781
    /**
1782
     * Returns the SQL to change a sequence on this platform.
1783 53762
     *
1784
     * @return string
1785
     *
1786 53708
     * @throws DBALException If not supported on this platform.
1787 53708
     */
1788
    public function getAlterSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1788
    public function getAlterSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1789 53708
    {
1790 53708
        throw DBALException::notSupported(__METHOD__);
1791
    }
1792 53762
1793
    /**
1794 53762
     * Returns the SQL to create a constraint on a table on this platform.
1795
     *
1796
     * @param Table|string $table
1797
     *
1798
     * @return string
1799
     *
1800
     * @throws InvalidArgumentException
1801
     */
1802
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1803
    {
1804
        if ($table instanceof Table) {
1805
            $table = $table->getQuotedName($this);
1806 58072
        }
1807
1808 58072
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1809 57058
1810
        $columnList = '(' . implode(', ', $constraint->getQuotedColumns($this)) . ')';
1811 58072
1812 58072
        $referencesClause = '';
1813
        if ($constraint instanceof Index) {
1814 58072
            if ($constraint->isPrimary()) {
1815
                $query .= ' PRIMARY KEY';
1816
            } elseif ($constraint->isUnique()) {
1817
                $query .= ' UNIQUE';
1818 58072
            } else {
1819 52068
                throw new InvalidArgumentException(
1820
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1821
                );
1822 58034
            }
1823 58034
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1824
            $query .= ' FOREIGN KEY';
1825 58034
1826
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1827
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1828
        }
1829
        $query .= ' ' . $columnList . $referencesClause;
1830
1831
        return $query;
1832
    }
1833 59192
1834
    /**
1835 59192
     * Returns the SQL to create an index on a table on this platform.
1836 45105
     *
1837
     * @param Table|string $table The name of the table on which the index is to be created.
1838
     *
1839 59182
     * @return string
1840
     *
1841
     * @throws InvalidArgumentException
1842
     */
1843
    public function getCreateIndexSQL(Index $index, $table)
1844
    {
1845
        if ($table instanceof Table) {
1846
            $table = $table->getQuotedName($this);
1847 56526
        }
1848
        $name    = $index->getQuotedName($this);
1849 56526
        $columns = $index->getColumns();
1850
1851
        if (count($columns) === 0) {
1852
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
1853
        }
1854
1855
        if ($index->isPrimary()) {
1856
            return $this->getCreatePrimaryKeySQL($index, $table);
1857
        }
1858
1859 54705
        $query  = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1860
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index);
1861 54705
1862
        return $query;
1863
    }
1864
1865 54705
    /**
1866
     * Adds condition for partial index.
1867
     *
1868
     * @return string
1869
     */
1870
    protected function getPartialIndexSQL(Index $index)
1871
    {
1872
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1873
            return ' WHERE ' . $index->getOption('where');
1874
        }
1875
1876
        return '';
1877 53150
    }
1878
1879 53150
    /**
1880
     * Adds additional flags for index generation.
1881
     *
1882
     * @return string
1883
     */
1884
    protected function getCreateIndexSQLFlags(Index $index)
1885
    {
1886
        return $index->isUnique() ? 'UNIQUE ' : '';
1887
    }
1888
1889
    /**
1890
     * Returns the SQL to create an unnamed primary key constraint.
1891
     *
1892
     * @param Table|string $table
1893
     *
1894
     * @return string
1895 60438
     */
1896
    public function getCreatePrimaryKeySQL(Index $index, $table)
1897 60438
    {
1898 54911
        if ($table instanceof Table) {
1899
            $table = $table->getQuotedName($this);
1900 54911
        }
1901
1902
        if ($index->getName() !=='primary' && $this->supportsNamedPrimaryConstraints()) {
1903 60438
            return $this->getCreateConstraintSQL($index, $table);
1904
        }
1905
1906
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')';
1907
    }
1908
1909
    /**
1910
     * Returns the SQL to create a named schema.
1911
     *
1912
     * @param string $schemaName
1913 60281
     *
1914
     * @return string
1915 60281
     *
1916
     * @throws DBALException If not supported on this platform.
1917 60281
     */
1918
    public function getCreateSchemaSQL($schemaName)
0 ignored issues
show
Unused Code introduced by
The parameter $schemaName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1918
    public function getCreateSchemaSQL(/** @scrutinizer ignore-unused */ $schemaName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1919
    {
1920
        throw DBALException::notSupported(__METHOD__);
1921
    }
1922
1923
    /**
1924
     * Quotes a string so that it can be safely used as a table or column name,
1925
     * even if it is a reserved word of the platform. This also detects identifier
1926
     * chains separated by dot and quotes them independently.
1927
     *
1928 58818
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1929
     * you SHOULD use them. In general, they end up causing way more
1930 58818
     * problems than they solve.
1931 2693
     *
1932
     * @param string $str The identifier name to be quoted.
1933
     *
1934 58818
     * @return string The quoted identifier string.
1935
     */
1936
    public function quoteIdentifier($str)
1937
    {
1938
        if (strpos($str, '.') !== false) {
1939
            $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str));
1940
1941
            return implode('.', $parts);
1942
        }
1943
1944
        return $this->quoteSingleIdentifier($str);
1945
    }
1946
1947
    /**
1948
     * Quotes a single identifier (no dot chain separation).
1949
     *
1950
     * @param string $str The identifier name to be quoted.
1951
     *
1952
     * @return string The quoted identifier string.
1953
     */
1954
    public function quoteSingleIdentifier($str)
1955
    {
1956 57923
        $c = $this->getIdentifierQuoteCharacter();
1957
1958 57923
        return $c . str_replace($c, $c . $c, $str) . $c;
1959 53773
    }
1960
1961
    /**
1962 57763
     * Returns the SQL to create a new foreign key.
1963 57727
     *
1964
     * @param ForeignKeyConstraint $foreignKey The foreign key constraint.
1965
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
1966 53557
     *
1967 53557
     * @return string
1968
     */
1969 53557
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1970
    {
1971 53557
        if ($table instanceof Table) {
1972
            $table = $table->getQuotedName($this);
1973
        }
1974
1975
        return 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1976
    }
1977
1978
    /**
1979 57167
     * Gets the SQL statements for altering an existing table.
1980
     *
1981 57167
     * This method returns an array of SQL statements, since some platforms need several statements.
1982 53727
     *
1983
     * @return string[]
1984
     *
1985 57053
     * @throws DBALException If not supported on this platform.
1986 57017
     */
1987
    public function getAlterTableSQL(TableDiff $diff)
1988
    {
1989 53557
        throw DBALException::notSupported(__METHOD__);
1990 53557
    }
1991
1992 53557
    /**
1993
     * @param mixed[] $columnSql
1994 53557
     *
1995
     * @return bool
1996
     */
1997
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
1998
    {
1999
        if ($this->_eventManager === null) {
2000
            return false;
2001
        }
2002 57982
2003
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
2004 57982
            return false;
2005 54819
        }
2006
2007
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
2008 57650
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
2009 57614
2010
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2011
2012 53557
        return $eventArgs->isDefaultPrevented();
2013 53557
    }
2014
2015 53557
    /**
2016
     * @param string[] $columnSql
2017 53557
     *
2018
     * @return bool
2019
     */
2020
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
2021
    {
2022
        if ($this->_eventManager === null) {
2023
            return false;
2024
        }
2025
2026 56938
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
2027
            return false;
2028 56938
        }
2029 53062
2030
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
2031
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
2032 56822
2033 54459
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2034
2035
        return $eventArgs->isDefaultPrevented();
2036 53557
    }
2037 53557
2038
    /**
2039 53557
     * @param string[] $columnSql
2040
     *
2041 53557
     * @return bool
2042
     */
2043
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
2044
    {
2045
        if ($this->_eventManager === null) {
2046
            return false;
2047
        }
2048
2049 58748
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
2050
            return false;
2051 58748
        }
2052 55157
2053
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
2054
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
2055 58078
2056 58042
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2057
2058
        return $eventArgs->isDefaultPrevented();
2059 53557
    }
2060 53557
2061
    /**
2062 53557
     * @param string   $oldColumnName
2063
     * @param string[] $columnSql
2064 53557
     *
2065
     * @return bool
2066
     */
2067
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
2068
    {
2069
        if ($this->_eventManager === null) {
2070 58602
            return false;
2071
        }
2072 58602
2073
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2074 58602
            return false;
2075 58602
        }
2076 58602
2077 56752
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2078
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2079 58602
2080 52733
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2081
2082
        return $eventArgs->isDefaultPrevented();
2083
    }
2084 58602
2085 57153
    /**
2086
     * @param string[] $sql
2087 58602
     *
2088 56804
     * @return bool
2089
     */
2090
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
2091 58602
    {
2092
        if ($this->_eventManager === null) {
2093
            return false;
2094
        }
2095
2096
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2097 58602
            return false;
2098
        }
2099 58602
2100 58602
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2101
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2102 58602
2103 54015
        $sql = array_merge($sql, $eventArgs->getSql());
2104
2105 58532
        return $eventArgs->isDefaultPrevented();
2106
    }
2107
2108 58602
    /**
2109 58602
     * @return string[]
2110 56841
     */
2111
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2112
    {
2113 58602
        $tableName = $diff->getName($this)->getQuotedName($this);
2114 52733
2115
        $sql = [];
2116
        if ($this->supportsForeignKeyConstraints()) {
2117
            foreach ($diff->removedForeignKeys as $foreignKey) {
2118 58602
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2119 56785
            }
2120
            foreach ($diff->changedForeignKeys as $foreignKey) {
2121
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2122 58602
            }
2123 56804
        }
2124
2125
        foreach ($diff->removedIndexes as $index) {
2126 58602
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2127 56984
        }
2128 56984
        foreach ($diff->changedIndexes as $index) {
2129 56984
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2130 56984
        }
2131
2132
        return $sql;
2133
    }
2134 58602
2135
    /**
2136
     * @return string[]
2137
     */
2138
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2139
    {
2140
        $sql     = [];
2141
        $newName = $diff->getNewName();
2142
2143
        if ($newName !== false) {
2144
            $tableName = $newName->getQuotedName($this);
2145
        } else {
2146 52642
            $tableName = $diff->getName($this)->getQuotedName($this);
2147
        }
2148
2149 52642
        if ($this->supportsForeignKeyConstraints()) {
2150 52642
            foreach ($diff->addedForeignKeys as $foreignKey) {
2151
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2152
            }
2153
2154
            foreach ($diff->changedForeignKeys as $foreignKey) {
2155
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2156
            }
2157
        }
2158
2159
        foreach ($diff->addedIndexes as $index) {
2160
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2161
        }
2162
2163
        foreach ($diff->changedIndexes as $index) {
2164
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2165
        }
2166
2167
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2168
            $oldIndexName = new Identifier($oldIndexName);
2169
            $sql          = array_merge(
2170
                $sql,
2171
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2172
            );
2173
        }
2174
2175
        return $sql;
2176
    }
2177
2178
    /**
2179
     * Returns the SQL for renaming an index on a table.
2180
     *
2181
     * @param string $oldIndexName The name of the index to rename from.
2182
     * @param Index  $index        The definition of the index to rename to.
2183
     * @param string $tableName    The table to rename the given index on.
2184
     *
2185
     * @return string[] The sequence of SQL statements for renaming the given index.
2186
     */
2187
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2188
    {
2189
        return [
2190
            $this->getDropIndexSQL($oldIndexName, $tableName),
2191
            $this->getCreateIndexSQL($index, $tableName),
2192
        ];
2193
    }
2194
2195 60749
    /**
2196
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2197 60749
     *
2198
     * @deprecated
2199 60749
     *
2200 60749
     * @return string[]
2201
     */
2202
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2203 60749
    {
2204
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2205
    }
2206
2207
    /**
2208
     * Gets declaration of a number of fields in bulk.
2209
     *
2210
     * @param mixed[][] $fields A multidimensional associative array.
2211
     *                          The first dimension determines the field name, while the second
2212
     *                          dimension is keyed with the name of the properties
2213
     *                          of the field being declared as array indexes. Currently, the types
2214
     *                          of supported field properties are as follows:
2215
     *
2216
     *      length
2217
     *          Integer value that determines the maximum length of the text
2218
     *          field. If this argument is missing the field should be
2219
     *          declared to have the longest length allowed by the DBMS.
2220
     *
2221
     *      default
2222
     *          Text value to be used as default for this field.
2223
     *
2224
     *      notnull
2225
     *          Boolean flag that indicates whether this field is constrained
2226
     *          to not be set to null.
2227
     *      charset
2228
     *          Text value with the default CHARACTER SET for this field.
2229
     *      collation
2230
     *          Text value with the default COLLATION for this field.
2231
     *      unique
2232
     *          unique constraint
2233
     *
2234
     * @return string
2235
     */
2236
    public function getColumnDeclarationListSQL(array $fields)
2237
    {
2238
        $queryFields = [];
2239 60196
2240
        foreach ($fields as $fieldName => $field) {
2241 60196
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2242 55318
        }
2243
2244 60168
        return implode(', ', $queryFields);
2245
    }
2246 60168
2247 60168
    /**
2248
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2249 60168
     * field to be used in statements like CREATE TABLE.
2250 60168
     *
2251
     * @param string  $name  The name the field to be declared.
2252 60168
     * @param mixed[] $field An associative array with the name of the properties
2253
     *                       of the field being declared as array indexes. Currently, the types
2254 60168
     *                       of supported field properties are as follows:
2255 60168
     *
2256
     *      length
2257 60168
     *          Integer value that determines the maximum length of the text
2258 60168
     *          field. If this argument is missing the field should be
2259
     *          declared to have the longest length allowed by the DBMS.
2260 60168
     *
2261 60168
     *      default
2262
     *          Text value to be used as default for this field.
2263 60168
     *
2264 54577
     *      notnull
2265
     *          Boolean flag that indicates whether this field is constrained
2266
     *          to not be set to null.
2267
     *      charset
2268 60196
     *          Text value with the default CHARACTER SET for this field.
2269
     *      collation
2270
     *          Text value with the default COLLATION for this field.
2271
     *      unique
2272
     *          unique constraint
2273
     *      check
2274
     *          column check constraint
2275
     *      columnDefinition
2276
     *          a string that defines the complete column
2277
     *
2278 57709
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2279
     */
2280 57709
    public function getColumnDeclarationSQL($name, array $field)
2281 57709
    {
2282 57709
        if (isset($field['columnDefinition'])) {
2283 57709
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2284
        } else {
2285 57709
            $default = $this->getDefaultValueDeclarationSQL($field);
2286
2287
            $charset = isset($field['charset']) && $field['charset'] ?
2288
                ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2289
2290
            $collation = isset($field['collation']) && $field['collation'] ?
2291
                ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2292
2293
            $notnull = isset($field['notnull']) && $field['notnull'] ? ' NOT NULL' : '';
2294
2295
            $unique = isset($field['unique']) && $field['unique'] ?
2296 60966
                ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2297
2298 60966
            $check = isset($field['check']) && $field['check'] ?
2299 60432
                ' ' . $field['check'] : '';
2300
2301
            $typeDecl  = $field['type']->getSQLDeclaration($field, $this);
2302 58654
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2303
2304 58654
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2305 13387
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2306
            }
2307
        }
2308 58630
2309
        return $name . ' ' . $columnDef;
2310 58630
    }
2311 57958
2312
    /**
2313
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2314 58572
     *
2315 58368
     * @param mixed[] $columnDef
2316
     *
2317
     * @return string
2318 58290
     */
2319 37867
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2320
    {
2321
        $columnDef['precision'] = ! isset($columnDef['precision']) || empty($columnDef['precision'])
2322 58290
            ? 10 : $columnDef['precision'];
2323 56476
        $columnDef['scale']     = ! isset($columnDef['scale']) || empty($columnDef['scale'])
2324
            ? 0 : $columnDef['scale'];
2325
2326 58011
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2327 57905
    }
2328
2329
    /**
2330 57984
     * Obtains DBMS specific SQL code portion needed to set a default value
2331
     * declaration to be used in statements like CREATE TABLE.
2332
     *
2333
     * @param mixed[] $field The field definition array.
2334
     *
2335
     * @return string DBMS specific SQL code portion needed to set a default value.
2336
     */
2337
    public function getDefaultValueDeclarationSQL($field)
2338
    {
2339
        if (! isset($field['default'])) {
2340
            return empty($field['notnull']) ? ' DEFAULT NULL' : '';
2341 55881
        }
2342
2343 55881
        $default = $field['default'];
2344 55881
2345 55881
        if (! isset($field['type'])) {
2346
            return " DEFAULT '" . $default . "'";
2347
        }
2348 55881
2349 54773
        $type = $field['type'];
2350
2351
        if ($type instanceof Types\PhpIntegerMappingType) {
2352 55881
            return ' DEFAULT ' . $default;
2353 54773
        }
2354
2355
        if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
2356
            return ' DEFAULT ' . $this->getCurrentTimestampSQL();
2357
        }
2358 55881
2359
        if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
2360
            return ' DEFAULT ' . $this->getCurrentTimeSQL();
2361
        }
2362
2363
        if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
2364
            return ' DEFAULT ' . $this->getCurrentDateSQL();
2365
        }
2366
2367
        if ($type instanceof Types\BooleanType) {
2368
            return " DEFAULT '" . $this->convertBooleans($default) . "'";
0 ignored issues
show
Bug introduced by
Are you sure $this->convertBooleans($default) of type array|integer|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2368
            return " DEFAULT '" . /** @scrutinizer ignore-type */ $this->convertBooleans($default) . "'";
Loading history...
2369
        }
2370
2371
        return ' DEFAULT ' . $this->quoteStringLiteral($default);
2372 53784
    }
2373
2374 53784
    /**
2375 53784
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2376
     * declaration to be used in statements like CREATE TABLE.
2377 53784
     *
2378
     * @param string[]|mixed[][] $definition The check definition.
2379
     *
2380
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2381 53784
     */
2382 53784
    public function getCheckDeclarationSQL(array $definition)
2383 53784
    {
2384
        $constraints = [];
2385
        foreach ($definition as $field => $def) {
2386
            if (is_string($def)) {
2387
                $constraints[] = 'CHECK (' . $def . ')';
2388
            } else {
2389
                if (isset($def['min'])) {
2390
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2391
                }
2392
2393
                if (isset($def['max'])) {
2394
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2395
                }
2396
            }
2397 55844
        }
2398
2399 55844
        return implode(', ', $constraints);
2400 55844
    }
2401
2402 55844
    /**
2403
     * Obtains DBMS specific SQL code portion needed to set a unique
2404
     * constraint declaration to be used in statements like CREATE TABLE.
2405
     *
2406 55844
     * @param string $name  The name of the unique constraint.
2407 55844
     * @param Index  $index The index definition.
2408 55844
     *
2409
     * @return string DBMS specific SQL code portion needed to set a constraint.
2410
     *
2411
     * @throws InvalidArgumentException
2412
     */
2413
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
2414
    {
2415
        $columns = $index->getColumns();
2416
        $name    = new Identifier($name);
2417
2418
        if (count($columns) === 0) {
2419
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2420 55326
        }
2421
2422 55326
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2423
            . $this->getIndexFieldDeclarationListSQL($index)
2424
            . ')' . $this->getPartialIndexSQL($index);
2425
    }
2426
2427
    /**
2428
     * Obtains DBMS specific SQL code portion needed to set an index
2429
     * declaration to be used in statements like CREATE TABLE.
2430
     *
2431 59332
     * @param string $name  The name of the index.
2432
     * @param Index  $index The index definition.
2433 59332
     *
2434 59244
     * @return string DBMS specific SQL code portion needed to set an index.
2435
     *
2436
     * @throws InvalidArgumentException
2437 26780
     */
2438
    public function getIndexDeclarationSQL($name, Index $index)
2439
    {
2440
        $columns = $index->getColumns();
2441 26780
        $name    = new Identifier($name);
2442
2443 26780
        if (count($columns) === 0) {
2444 26780
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2445
        }
2446
2447 26780
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2448
            . $this->getIndexFieldDeclarationListSQL($index)
2449
            . ')' . $this->getPartialIndexSQL($index);
2450
    }
2451 26780
2452
    /**
2453
     * Obtains SQL code portion needed to create a custom column,
2454
     * e.g. when a field has the "columnDefinition" keyword.
2455
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2456
     *
2457
     * @param mixed[] $columnDef
2458
     *
2459
     * @return string
2460
     */
2461
    public function getCustomTypeDeclarationSQL(array $columnDef)
2462
    {
2463
        return $columnDef['columnDefinition'];
2464
    }
2465
2466
    /**
2467
     * Obtains DBMS specific SQL code portion needed to set an index
2468
     * declaration to be used in statements like CREATE TABLE.
2469
     *
2470
     * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method
2471
     */
2472
    public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string
2473
    {
2474
        if ($columnsOrIndex instanceof Index) {
2475
            return implode(', ', $columnsOrIndex->getQuotedColumns($this));
2476
        }
2477
2478
        if (! is_array($columnsOrIndex)) {
0 ignored issues
show
introduced by
The condition is_array($columnsOrIndex) is always true.
Loading history...
2479
            throw new InvalidArgumentException('Fields argument should be an Index or array.');
2480 45988
        }
2481
2482 45988
        $ret = [];
2483
2484
        foreach ($columnsOrIndex as $column => $definition) {
2485
            if (is_array($definition)) {
2486
                $ret[] = $column;
2487
            } else {
2488
                $ret[] = $definition;
2489
            }
2490
        }
2491
2492 58971
        return implode(', ', $ret);
2493
    }
2494 58971
2495 58947
    /**
2496
     * Returns the required SQL string that fits between CREATE ... TABLE
2497 58947
     * to create the table as a temporary table.
2498
     *
2499
     * Should be overridden in driver classes to return the correct string for the
2500
     * specific database type.
2501
     *
2502
     * The default is to return the string "TEMPORARY" - this will result in a
2503
     * SQL error for any database that does not support temporary tables, or that
2504
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2505
     *
2506
     * @return string The string required to be placed between "CREATE" and "TABLE"
2507
     *                to generate a temporary table, if possible.
2508 58915
     */
2509
    public function getTemporaryTableSQL()
2510 58915
    {
2511 58915
        return 'TEMPORARY';
2512 26274
    }
2513
2514 58915
    /**
2515 56569
     * Some vendors require temporary table names to be qualified specially.
2516
     *
2517
     * @param string $tableName
2518 58915
     *
2519
     * @return string
2520
     */
2521
    public function getTemporaryTableName($tableName)
2522
    {
2523
        return $tableName;
2524
    }
2525
2526
    /**
2527
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2528
     * of a field declaration to be used in statements like CREATE TABLE.
2529
     *
2530 57352
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2531
     *                of a field declaration.
2532 57352
     */
2533 242
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2534 57352
    {
2535 55388
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2536 55330
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2537 55288
2538 55244
        return $sql;
2539 57318
    }
2540
2541 54038
    /**
2542
     * Returns the FOREIGN KEY query section dealing with non-standard options
2543
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2544
     *
2545
     * @param ForeignKeyConstraint $foreignKey The foreign key definition.
2546
     *
2547
     * @return string
2548
     */
2549
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2550
    {
2551
        $query = '';
2552
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2553 58891
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2554
        }
2555 58891
        if ($foreignKey->hasOption('onDelete')) {
2556 58891
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2557 58778
        }
2558
2559 58891
        return $query;
2560
    }
2561 58891
2562
    /**
2563
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2564 58891
     *
2565
     * @param string $action The foreign key referential action.
2566
     *
2567 58891
     * @return string
2568
     *
2569
     * @throws InvalidArgumentException If unknown referential action given.
2570
     */
2571 58891
    public function getForeignKeyReferentialActionSQL($action)
2572 58891
    {
2573 58891
        $upper = strtoupper($action);
2574 58891
        switch ($upper) {
2575
            case 'CASCADE':
2576
            case 'SET NULL':
2577
            case 'NO ACTION':
2578
            case 'RESTRICT':
2579
            case 'SET DEFAULT':
2580
                return $upper;
2581
            default:
2582
                throw new InvalidArgumentException('Invalid foreign key action: ' . $upper);
2583
        }
2584
    }
2585
2586
    /**
2587
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2588
     * of a field declaration to be used in statements like CREATE TABLE.
2589
     *
2590
     * @return string
2591
     *
2592
     * @throws InvalidArgumentException
2593
     */
2594
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2595
    {
2596
        $sql = '';
2597
        if (strlen($foreignKey->getName())) {
2598
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2599
        }
2600
        $sql .= 'FOREIGN KEY (';
2601
2602
        if (count($foreignKey->getLocalColumns()) === 0) {
2603
            throw new InvalidArgumentException("Incomplete definition. 'local' required.");
2604
        }
2605
        if (count($foreignKey->getForeignColumns()) === 0) {
2606
            throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
2607
        }
2608
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2609
            throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2610
        }
2611
2612 18679
        return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this))
2613
            . ') REFERENCES '
2614 18679
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2615
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2616
    }
2617
2618
    /**
2619
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2620
     * of a field declaration to be used in statements like CREATE TABLE.
2621
     *
2622
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2623 10
     *                of a field declaration.
2624
     */
2625 10
    public function getUniqueFieldDeclarationSQL()
2626
    {
2627
        return 'UNIQUE';
2628
    }
2629
2630
    /**
2631
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2632
     * of a field declaration to be used in statements like CREATE TABLE.
2633
     *
2634 47277
     * @param string $charset The name of the charset.
2635
     *
2636 47277
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2637
     *                of a field declaration.
2638
     */
2639
    public function getColumnCharsetDeclarationSQL($charset)
0 ignored issues
show
Unused Code introduced by
The parameter $charset is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2639
    public function getColumnCharsetDeclarationSQL(/** @scrutinizer ignore-unused */ $charset)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2640
    {
2641
        return '';
2642
    }
2643
2644
    /**
2645
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2646
     * of a field declaration to be used in statements like CREATE TABLE.
2647
     *
2648
     * @param string $collation The name of the collation.
2649
     *
2650
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2651
     *                of a field declaration.
2652
     */
2653 56217
    public function getColumnCollationDeclarationSQL($collation)
2654
    {
2655 56217
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2656
    }
2657
2658
    /**
2659
     * Whether the platform prefers sequences for ID generation.
2660
     * Subclasses should override this method to return TRUE if they prefer sequences.
2661
     *
2662
     * @return bool
2663 56217
     */
2664 56215
    public function prefersSequences()
2665
    {
2666
        return false;
2667 56217
    }
2668
2669
    /**
2670
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2671
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2672
     *
2673
     * @return bool
2674
     */
2675
    public function prefersIdentityColumns()
2676
    {
2677
        return false;
2678
    }
2679 55685
2680
    /**
2681 55685
     * Some platforms need the boolean values to be converted.
2682
     *
2683
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2684
     *
2685
     * Note: if the input is not a boolean the original input might be returned.
2686
     *
2687
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2688
     * This method should handle the literal case
2689
     *
2690
     * @param mixed $item A boolean or an array of them.
2691
     *
2692
     * @return mixed A boolean database value or an array of them.
2693
     */
2694 51062
    public function convertBooleans($item)
2695
    {
2696 51062
        if (is_array($item)) {
2697
            foreach ($item as $k => $value) {
2698
                if (! is_bool($value)) {
2699
                    continue;
2700
                }
2701
2702
                $item[$k] = (int) $value;
2703
            }
2704 56900
        } elseif (is_bool($item)) {
2705
            $item = (int) $item;
2706 56900
        }
2707
2708
        return $item;
2709
    }
2710
2711
    /**
2712
     * Some platforms have boolean literals that needs to be correctly converted
2713
     *
2714 30305
     * The default conversion tries to convert value into bool "(bool)$item"
2715
     *
2716 30305
     * @param mixed $item
2717
     *
2718
     * @return bool|null
2719
     */
2720
    public function convertFromBoolean($item)
2721
    {
2722
        return $item === null ? null: (bool) $item;
2723
    }
2724 58056
2725
    /**
2726 58056
     * This method should handle the prepared statements case. When there is no
2727
     * distinction, it's OK to use the same method.
2728
     *
2729
     * Note: if the input is not a boolean the original input might be returned.
2730
     *
2731
     * @param mixed $item A boolean or an array of them.
2732
     *
2733
     * @return mixed A boolean database value or an array of them.
2734
     */
2735
    public function convertBooleansToDatabaseValue($item)
2736
    {
2737
        return $this->convertBooleans($item);
2738 52370
    }
2739
2740 22
    /**
2741 52348
     * Returns the SQL specific for the platform to get the current date.
2742 52370
     *
2743 52348
     * @return string
2744 52370
     */
2745 52348
    public function getCurrentDateSQL()
2746 52370
    {
2747 52348
        return 'CURRENT_DATE';
2748 52370
    }
2749
2750
    /**
2751
     * Returns the SQL specific for the platform to get the current time.
2752
     *
2753
     * @return string
2754
     */
2755
    public function getCurrentTimeSQL()
2756
    {
2757
        return 'CURRENT_TIME';
2758
    }
2759 2492
2760
    /**
2761 2492
     * Returns the SQL specific for the platform to get the current timestamp
2762
     *
2763
     * @return string
2764
     */
2765
    public function getCurrentTimestampSQL()
2766
    {
2767
        return 'CURRENT_TIMESTAMP';
2768
    }
2769
2770
    /**
2771
     * Returns the SQL for a given transaction isolation level Connection constant.
2772
     *
2773
     * @param int $level
2774
     *
2775
     * @return string
2776
     *
2777
     * @throws InvalidArgumentException
2778
     */
2779
    protected function _getTransactionIsolationLevelSQL($level)
2780
    {
2781
        switch ($level) {
2782
            case TransactionIsolationLevel::READ_UNCOMMITTED:
2783
                return 'READ UNCOMMITTED';
2784
            case TransactionIsolationLevel::READ_COMMITTED:
2785
                return 'READ COMMITTED';
2786
            case TransactionIsolationLevel::REPEATABLE_READ:
2787
                return 'REPEATABLE READ';
2788
            case TransactionIsolationLevel::SERIALIZABLE:
2789
                return 'SERIALIZABLE';
2790
            default:
2791
                throw new InvalidArgumentException('Invalid isolation level:' . $level);
2792
        }
2793
    }
2794
2795
    /**
2796
     * @return string
2797
     *
2798
     * @throws DBALException If not supported on this platform.
2799
     */
2800
    public function getListDatabasesSQL()
2801
    {
2802
        throw DBALException::notSupported(__METHOD__);
2803
    }
2804
2805
    /**
2806
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2807
     *
2808
     * @return string
2809
     *
2810
     * @throws DBALException If not supported on this platform.
2811
     */
2812
    public function getListNamespacesSQL()
2813
    {
2814
        throw DBALException::notSupported(__METHOD__);
2815
    }
2816
2817
    /**
2818
     * @param string $database
2819
     *
2820
     * @return string
2821
     *
2822
     * @throws DBALException If not supported on this platform.
2823
     */
2824
    public function getListSequencesSQL($database)
2825
    {
2826
        throw DBALException::notSupported(__METHOD__);
2827
    }
2828
2829
    /**
2830
     * @param string $table
2831
     *
2832
     * @return string
2833
     *
2834
     * @throws DBALException If not supported on this platform.
2835
     */
2836
    public function getListTableConstraintsSQL($table)
2837
    {
2838
        throw DBALException::notSupported(__METHOD__);
2839
    }
2840
2841
    /**
2842
     * @param string      $table
2843
     * @param string|null $database
2844
     *
2845
     * @return string
2846
     *
2847
     * @throws DBALException If not supported on this platform.
2848
     */
2849
    public function getListTableColumnsSQL($table, $database = null)
2850
    {
2851
        throw DBALException::notSupported(__METHOD__);
2852
    }
2853
2854
    /**
2855
     * @return string
2856
     *
2857
     * @throws DBALException If not supported on this platform.
2858
     */
2859
    public function getListTablesSQL()
2860
    {
2861
        throw DBALException::notSupported(__METHOD__);
2862
    }
2863
2864
    /**
2865
     * @return string
2866
     *
2867
     * @throws DBALException If not supported on this platform.
2868
     */
2869
    public function getListUsersSQL()
2870
    {
2871
        throw DBALException::notSupported(__METHOD__);
2872
    }
2873
2874
    /**
2875
     * Returns the SQL to list all views of a database or user.
2876
     *
2877
     * @param string $database
2878
     *
2879
     * @return string
2880
     *
2881
     * @throws DBALException If not supported on this platform.
2882
     */
2883
    public function getListViewsSQL($database)
2884
    {
2885
        throw DBALException::notSupported(__METHOD__);
2886
    }
2887
2888
    /**
2889
     * Returns the list of indexes for the current database.
2890
     *
2891
     * The current database parameter is optional but will always be passed
2892
     * when using the SchemaManager API and is the database the given table is in.
2893
     *
2894
     * Attention: Some platforms only support currentDatabase when they
2895
     * are connected with that database. Cross-database information schema
2896
     * requests may be impossible.
2897
     *
2898
     * @param string $table
2899
     * @param string $currentDatabase
2900
     *
2901
     * @return string
2902
     *
2903
     * @throws DBALException If not supported on this platform.
2904
     */
2905
    public function getListTableIndexesSQL($table, $currentDatabase = null)
2906
    {
2907
        throw DBALException::notSupported(__METHOD__);
2908
    }
2909
2910
    /**
2911
     * @param string $table
2912
     *
2913
     * @return string
2914
     *
2915
     * @throws DBALException If not supported on this platform.
2916
     */
2917
    public function getListTableForeignKeysSQL($table)
2918
    {
2919
        throw DBALException::notSupported(__METHOD__);
2920
    }
2921
2922
    /**
2923
     * @param string $name
2924
     * @param string $sql
2925
     *
2926
     * @return string
2927
     *
2928
     * @throws DBALException If not supported on this platform.
2929
     */
2930
    public function getCreateViewSQL($name, $sql)
2931
    {
2932
        throw DBALException::notSupported(__METHOD__);
2933
    }
2934
2935
    /**
2936
     * @param string $name
2937
     *
2938
     * @return string
2939
     *
2940
     * @throws DBALException If not supported on this platform.
2941 44001
     */
2942
    public function getDropViewSQL($name)
2943 44001
    {
2944
        throw DBALException::notSupported(__METHOD__);
2945
    }
2946
2947
    /**
2948
     * Returns the SQL snippet to drop an existing sequence.
2949
     *
2950
     * @param Sequence|string $sequence
2951
     *
2952
     * @return string
2953
     *
2954
     * @throws DBALException If not supported on this platform.
2955
     */
2956
    public function getDropSequenceSQL($sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2956
    public function getDropSequenceSQL(/** @scrutinizer ignore-unused */ $sequence)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2957
    {
2958
        throw DBALException::notSupported(__METHOD__);
2959
    }
2960
2961
    /**
2962
     * @param string $sequenceName
2963
     *
2964
     * @return string
2965
     *
2966
     * @throws DBALException If not supported on this platform.
2967
     */
2968
    public function getSequenceNextValSQL($sequenceName)
0 ignored issues
show
Unused Code introduced by
The parameter $sequenceName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2968
    public function getSequenceNextValSQL(/** @scrutinizer ignore-unused */ $sequenceName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2969
    {
2970
        throw DBALException::notSupported(__METHOD__);
2971
    }
2972
2973
    /**
2974
     * Returns the SQL to create a new database.
2975
     *
2976
     * @param string $database The name of the database that should be created.
2977
     *
2978
     * @return string
2979
     *
2980
     * @throws DBALException If not supported on this platform.
2981
     */
2982 33834
    public function getCreateDatabaseSQL($database)
2983
    {
2984 33834
        throw DBALException::notSupported(__METHOD__);
2985
    }
2986
2987
    /**
2988
     * Returns the SQL to set the transaction isolation level.
2989
     *
2990
     * @param int $level
2991
     *
2992
     * @return string
2993
     *
2994
     * @throws DBALException If not supported on this platform.
2995
     */
2996
    public function getSetTransactionIsolationSQL($level)
2997
    {
2998
        throw DBALException::notSupported(__METHOD__);
2999
    }
3000
3001
    /**
3002
     * Obtains DBMS specific SQL to be used to create datetime fields in
3003
     * statements like CREATE TABLE.
3004
     *
3005
     * @param mixed[] $fieldDeclaration
3006
     *
3007
     * @return string
3008
     *
3009
     * @throws DBALException If not supported on this platform.
3010
     */
3011
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
3012
    {
3013
        throw DBALException::notSupported(__METHOD__);
3014
    }
3015
3016
    /**
3017
     * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields.
3018
     *
3019
     * @param mixed[] $fieldDeclaration
3020
     *
3021
     * @return string
3022 54810
     */
3023
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
3024 54810
    {
3025
        return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
3026
    }
3027
3028
    /**
3029
     * Obtains DBMS specific SQL to be used to create date fields in statements
3030
     * like CREATE TABLE.
3031
     *
3032
     * @param mixed[] $fieldDeclaration
3033
     *
3034
     * @return string
3035
     *
3036
     * @throws DBALException If not supported on this platform.
3037
     */
3038
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
3039
    {
3040
        throw DBALException::notSupported(__METHOD__);
3041
    }
3042
3043
    /**
3044
     * Obtains DBMS specific SQL to be used to create time fields in statements
3045
     * like CREATE TABLE.
3046 36262
     *
3047
     * @param mixed[] $fieldDeclaration
3048 36262
     *
3049
     * @return string
3050
     *
3051
     * @throws DBALException If not supported on this platform.
3052
     */
3053
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
3054
    {
3055
        throw DBALException::notSupported(__METHOD__);
3056
    }
3057
3058
    /**
3059 6
     * @param mixed[] $fieldDeclaration
3060
     *
3061 6
     * @return string
3062
     */
3063
    public function getFloatDeclarationSQL(array $fieldDeclaration)
3064
    {
3065
        return 'DOUBLE PRECISION';
3066
    }
3067
3068
    /**
3069
     * Gets the default transaction isolation level of the platform.
3070
     *
3071
     * @see TransactionIsolationLevel
3072
     *
3073 54372
     * @return int The default isolation level.
3074
     */
3075 54372
    public function getDefaultTransactionIsolationLevel()
3076
    {
3077
        return TransactionIsolationLevel::READ_COMMITTED;
3078
    }
3079
3080
    /* supports*() methods */
3081
3082
    /**
3083
     * Whether the platform supports sequences.
3084
     *
3085
     * @return bool
3086
     */
3087
    public function supportsSequences()
3088
    {
3089
        return false;
3090 53085
    }
3091
3092 53085
    /**
3093
     * Whether the platform supports identity columns.
3094
     *
3095
     * Identity columns are columns that receive an auto-generated value from the
3096
     * database on insert of a row.
3097
     *
3098
     * @return bool
3099
     */
3100 8
    public function supportsIdentityColumns()
3101
    {
3102 8
        return false;
3103
    }
3104
3105
    /**
3106
     * Whether the platform emulates identity columns through sequences.
3107
     *
3108
     * Some platforms that do not support identity columns natively
3109
     * but support sequences can emulate identity columns by using
3110 57808
     * sequences.
3111
     *
3112 57808
     * @return bool
3113
     */
3114
    public function usesSequenceEmulatedIdentityColumns()
3115
    {
3116
        return false;
3117
    }
3118 57859
3119
    /**
3120 57859
     * Returns the name of the sequence for a particular identity column in a particular table.
3121
     *
3122
     * @see    usesSequenceEmulatedIdentityColumns
3123
     *
3124
     * @param string $tableName  The name of the table to return the sequence name for.
3125
     * @param string $columnName The name of the identity column in the table to return the sequence name for.
3126
     *
3127
     * @return string
3128 56983
     *
3129
     * @throws DBALException If not supported on this platform.
3130 56983
     */
3131
    public function getIdentitySequenceName($tableName, $columnName)
3132
    {
3133
        throw DBALException::notSupported(__METHOD__);
3134
    }
3135
3136
    /**
3137
     * Whether the platform supports indexes.
3138 8
     *
3139
     * @return bool
3140 8
     */
3141
    public function supportsIndexes()
3142
    {
3143
        return true;
3144
    }
3145
3146
    /**
3147
     * Whether the platform supports partial indexes.
3148 58361
     *
3149
     * @return bool
3150 58361
     */
3151
    public function supportsPartialIndexes()
3152
    {
3153
        return false;
3154
    }
3155
3156
    /**
3157
     * Whether the platform supports indexes with column length definitions.
3158 55454
     */
3159
    public function supportsColumnLengthIndexes() : bool
3160 55454
    {
3161
        return false;
3162
    }
3163
3164
    /**
3165
     * Whether the platform supports altering tables.
3166
     *
3167
     * @return bool
3168 8
     */
3169
    public function supportsAlterTable()
3170 8
    {
3171
        return true;
3172
    }
3173
3174
    /**
3175
     * Whether the platform supports transactions.
3176
     *
3177
     * @return bool
3178 59674
     */
3179
    public function supportsTransactions()
3180 59674
    {
3181
        return true;
3182
    }
3183
3184
    /**
3185
     * Whether the platform supports savepoints.
3186
     *
3187
     * @return bool
3188 58923
     */
3189
    public function supportsSavepoints()
3190 58923
    {
3191
        return true;
3192
    }
3193
3194
    /**
3195
     * Whether the platform supports releasing savepoints.
3196
     *
3197
     * @return bool
3198 36272
     */
3199
    public function supportsReleaseSavepoints()
3200 36272
    {
3201
        return $this->supportsSavepoints();
3202
    }
3203
3204
    /**
3205
     * Whether the platform supports primary key constraints.
3206
     *
3207
     * @return bool
3208
     */
3209
    public function supportsPrimaryConstraints()
3210
    {
3211
        return true;
3212 8
    }
3213
3214 8
    /**
3215
     * Whether the platform supports named primary key constraints.
3216
     *
3217
     * @return bool
3218
     */
3219
    public function supportsNamedPrimaryConstraints()
3220
    {
3221
        return true;
3222
    }
3223
3224
    /**
3225
     * Whether the platform supports foreign key constraints.
3226
     *
3227
     * @return bool
3228
     */
3229
    public function supportsForeignKeyConstraints()
3230
    {
3231
        return true;
3232
    }
3233
3234
    /**
3235
     * Whether this platform supports onUpdate in foreign key constraints.
3236 54434
     *
3237
     * @return bool
3238 54434
     */
3239
    public function supportsForeignKeyOnUpdate()
3240
    {
3241
        return $this->supportsForeignKeyConstraints();
3242
    }
3243
3244
    /**
3245
     * Whether the platform supports database schemas.
3246 8
     *
3247
     * @return bool
3248 8
     */
3249
    public function supportsSchemas()
3250
    {
3251
        return false;
3252
    }
3253
3254
    /**
3255
     * Whether this platform can emulate schemas.
3256 57216
     *
3257
     * Platforms that either support or emulate schemas don't automatically
3258 57216
     * filter a schema for the namespaced elements in {@link
3259
     * AbstractManager#createSchema}.
3260
     *
3261
     * @return bool
3262
     */
3263
    public function canEmulateSchemas()
3264
    {
3265
        return false;
3266 57536
    }
3267
3268 57536
    /**
3269
     * Returns the default schema name.
3270
     *
3271
     * @return string
3272
     *
3273
     * @throws DBALException If not supported on this platform.
3274
     */
3275
    public function getDefaultSchemaName()
3276 58556
    {
3277
        throw DBALException::notSupported(__METHOD__);
3278 58556
    }
3279
3280
    /**
3281
     * Whether this platform supports create database.
3282
     *
3283
     * Some databases don't allow to create and drop databases at all or only with certain tools.
3284
     *
3285
     * @return bool
3286 58781
     */
3287
    public function supportsCreateDropDatabase()
3288 58781
    {
3289
        return true;
3290
    }
3291
3292
    /**
3293
     * Whether the platform supports getting the affected rows of a recent update/delete type query.
3294
     *
3295
     * @return bool
3296
     */
3297
    public function supportsGettingAffectedRows()
3298
    {
3299
        return true;
3300
    }
3301
3302
    /**
3303
     * Whether this platform support to add inline column comments as postfix.
3304
     *
3305
     * @return bool
3306 56943
     */
3307
    public function supportsInlineColumnComments()
3308 56943
    {
3309
        return false;
3310
    }
3311
3312
    /**
3313
     * Whether this platform support the proprietary syntax "COMMENT ON asset".
3314
     *
3315
     * @return bool
3316
     */
3317
    public function supportsCommentOnStatement()
3318
    {
3319
        return false;
3320
    }
3321
3322
    /**
3323
     * Does this platform have native guid type.
3324
     *
3325
     * @return bool
3326
     */
3327 54564
    public function hasNativeGuidType()
3328
    {
3329 54564
        return false;
3330
    }
3331
3332
    /**
3333
     * Does this platform have native JSON type.
3334
     *
3335
     * @return bool
3336
     */
3337
    public function hasNativeJsonType()
3338 34103
    {
3339
        return false;
3340 34103
    }
3341
3342
    /**
3343
     * @deprecated
3344
     *
3345
     * @return string
3346
     *
3347
     * @todo Remove in 3.0
3348
     */
3349 50627
    public function getIdentityColumnNullInsertSQL()
3350
    {
3351 50627
        return '';
3352
    }
3353
3354
    /**
3355
     * Whether this platform supports views.
3356
     *
3357
     * @return bool
3358
     */
3359
    public function supportsViews()
3360 43354
    {
3361
        return true;
3362 43354
    }
3363
3364
    /**
3365
     * Does this platform support column collation?
3366
     *
3367
     * @return bool
3368
     */
3369
    public function supportsColumnCollation()
3370
    {
3371
        return false;
3372
    }
3373
3374
    /**
3375
     * Gets the format string, as accepted by the date() function, that describes
3376 58883
     * the format of a stored datetime value of this platform.
3377
     *
3378 58883
     * @return string The format string.
3379 58827
     */
3380
    public function getDateTimeFormatString()
3381
    {
3382 58883
        return 'Y-m-d H:i:s';
3383
    }
3384 58883
3385
    /**
3386
     * Gets the format string, as accepted by the date() function, that describes
3387
     * the format of a stored datetime with timezone value of this platform.
3388
     *
3389
     * @return string The format string.
3390
     */
3391 58883
    public function getDateTimeTzFormatString()
3392
    {
3393
        return 'Y-m-d H:i:s';
3394
    }
3395
3396
    /**
3397
     * Gets the format string, as accepted by the date() function, that describes
3398 58883
     * the format of a stored date value of this platform.
3399
     *
3400
     * @return string The format string.
3401
     */
3402
    public function getDateFormatString()
3403
    {
3404
        return 'Y-m-d';
3405
    }
3406
3407
    /**
3408
     * Gets the format string, as accepted by the date() function, that describes
3409
     * the format of a stored time value of this platform.
3410 47169
     *
3411
     * @return string The format string.
3412 47169
     */
3413 47157
    public function getTimeFormatString()
3414
    {
3415
        return 'H:i:s';
3416 47169
    }
3417 20433
3418
    /**
3419
     * Adds an driver-specific LIMIT clause to the query.
3420 47169
     *
3421
     * @param string   $query
3422
     * @param int|null $limit
3423
     * @param int|null $offset
3424
     *
3425
     * @return string
3426
     *
3427
     * @throws DBALException
3428 58326
     */
3429
    final public function modifyLimitQuery($query, $limit, $offset = null)
3430 58326
    {
3431
        if ($limit !== null) {
3432
            $limit = (int) $limit;
3433
        }
3434
3435
        $offset = (int) $offset;
3436
3437
        if ($offset < 0) {
3438
            throw new DBALException(sprintf(
3439
                'Offset must be a positive integer or zero, %d given',
3440
                $offset
3441
            ));
3442
        }
3443
3444
        if ($offset > 0 && ! $this->supportsLimitOffset()) {
3445
            throw new DBALException(sprintf(
3446
                'Platform %s does not support offset values in limit queries.',
3447
                $this->getName()
3448
            ));
3449
        }
3450
3451
        return $this->doModifyLimitQuery($query, $limit, $offset);
3452
    }
3453
3454
    /**
3455
     * Adds an platform-specific LIMIT clause to the query.
3456
     *
3457
     * @param string   $query
3458
     * @param int|null $limit
3459
     * @param int|null $offset
3460
     *
3461
     * @return string
3462
     */
3463 58062
    protected function doModifyLimitQuery($query, $limit, $offset)
3464
    {
3465 58062
        if ($limit !== null) {
3466
            $query .= ' LIMIT ' . $limit;
3467
        }
3468
3469
        if ($offset > 0) {
3470
            $query .= ' OFFSET ' . $offset;
3471
        }
3472
3473
        return $query;
3474
    }
3475
3476 31033
    /**
3477
     * Whether the database platform support offsets in modify limit clauses.
3478 31033
     *
3479
     * @return bool
3480
     */
3481
    public function supportsLimitOffset()
3482
    {
3483
        return true;
3484
    }
3485
3486
    /**
3487
     * Gets the character casing of a column in an SQL result set of this platform.
3488
     *
3489
     * @param string $column The column name for which to get the correct character casing.
3490
     *
3491
     * @return string The column name in the character casing used in SQL result sets.
3492 54952
     */
3493
    public function getSQLResultCasing($column)
3494 54952
    {
3495
        return $column;
3496 54952
    }
3497
3498
    /**
3499
     * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
3500
     * by restrictions of the platform, like a maximum length.
3501
     *
3502
     * @param string $schemaElementName
3503
     *
3504 59712
     * @return string
3505
     */
3506 59712
    public function fixSchemaElementName($schemaElementName)
3507
    {
3508 59712
        return $schemaElementName;
3509
    }
3510
3511
    /**
3512
     * Maximum length of any given database identifier, like tables or column names.
3513
     *
3514
     * @return int
3515
     */
3516
    public function getMaxIdentifierLength()
3517
    {
3518 52100
        return 63;
3519
    }
3520 52100
3521
    /**
3522
     * Returns the insert SQL for an empty insert statement.
3523
     *
3524
     * @param string $tableName
3525
     * @param string $identifierColumnName
3526
     *
3527
     * @return string
3528
     */
3529
    public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
3530 52098
    {
3531
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
3532 52098
    }
3533
3534
    /**
3535
     * Generates a Truncate Table SQL statement for a given table.
3536
     *
3537
     * Cascade is not supported on many platforms but would optionally cascade the truncate by
3538
     * following the foreign keys.
3539
     *
3540
     * @param string $tableName
3541
     * @param bool   $cascade
3542 52100
     *
3543
     * @return string
3544 52100
     */
3545
    public function getTruncateTableSQL($tableName, $cascade = false)
0 ignored issues
show
Unused Code introduced by
The parameter $cascade is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

3545
    public function getTruncateTableSQL($tableName, /** @scrutinizer ignore-unused */ $cascade = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3546
    {
3547
        $tableIdentifier = new Identifier($tableName);
3548
3549
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3550
    }
3551
3552
    /**
3553
     * This is for test reasons, many vendors have special requirements for dummy statements.
3554 62221
     *
3555
     * @return string
3556
     */
3557 62221
    public function getDummySelectSQL()
3558 62087
    {
3559
        $expression = func_num_args() > 0 ? func_get_arg(0) : '1';
3560
3561 61887
        return sprintf('SELECT %s', $expression);
3562 61887
    }
3563 61887
3564
    /**
3565
     * Returns the SQL to create a new savepoint.
3566
     *
3567
     * @param string $savepoint
3568 61887
     *
3569
     * @return string
3570 61887
     */
3571
    public function createSavePoint($savepoint)
3572
    {
3573
        return 'SAVEPOINT ' . $savepoint;
3574
    }
3575
3576
    /**
3577
     * Returns the SQL to release a savepoint.
3578
     *
3579
     * @param string $savepoint
3580
     *
3581
     * @return string
3582
     */
3583
    public function releaseSavePoint($savepoint)
3584
    {
3585
        return 'RELEASE SAVEPOINT ' . $savepoint;
3586
    }
3587
3588
    /**
3589
     * Returns the SQL to rollback a savepoint.
3590
     *
3591
     * @param string $savepoint
3592
     *
3593
     * @return string
3594
     */
3595 59227
    public function rollbackSavePoint($savepoint)
3596
    {
3597 59227
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3598
    }
3599 59227
3600
    /**
3601
     * Returns the keyword list instance of this platform.
3602
     *
3603
     * @return KeywordList
3604
     *
3605
     * @throws DBALException If no keyword list is specified.
3606
     */
3607 59263
    final public function getReservedKeywordsList()
3608
    {
3609 59263
        // Check for an existing instantiation of the keywords class.
3610
        if ($this->_keywords) {
3611
            return $this->_keywords;
3612
        }
3613
3614
        $class    = $this->getReservedKeywordsClass();
3615
        $keywords = new $class();
3616
        if (! $keywords instanceof KeywordList) {
3617
            throw DBALException::notSupported(__METHOD__);
3618
        }
3619
3620 58816
        // Store the instance so it doesn't need to be generated on every request.
3621
        $this->_keywords = $keywords;
3622 58816
3623 58816
        return $keywords;
3624 58816
    }
3625 58816
3626
    /**
3627
     * Returns the class name of the reserved keywords list.
3628
     *
3629 58816
     * @return string
3630
     *
3631 58816
     * @throws DBALException If not supported on this platform.
3632
     */
3633
    protected function getReservedKeywordsClass()
3634
    {
3635
        throw DBALException::notSupported(__METHOD__);
3636
    }
3637
3638
    /**
3639
     * Quotes a literal string.
3640
     * This method is NOT meant to fix SQL injections!
3641
     * It is only meant to escape this platform's string literal
3642
     * quote character inside the given literal string.
3643
     *
3644
     * @param string $str The literal string to be quoted.
3645
     *
3646
     * @return string The quoted literal string.
3647
     */
3648
    public function quoteStringLiteral($str)
3649
    {
3650
        $c = $this->getStringLiteralQuoteCharacter();
3651
3652
        return $c . str_replace($c, $c . $c, $str) . $c;
3653
    }
3654
3655
    /**
3656
     * Gets the character used for string literal quoting.
3657
     *
3658
     * @return string
3659
     */
3660
    public function getStringLiteralQuoteCharacter()
3661
    {
3662
        return "'";
3663
    }
3664
3665
    /**
3666
     * Escapes metacharacters in a string intended to be used with a LIKE
3667
     * operator.
3668
     *
3669
     * @param string $inputString a literal, unquoted string
3670
     * @param string $escapeChar  should be reused by the caller in the LIKE
3671
     *                            expression.
3672
     */
3673
    final public function escapeStringForLike(string $inputString, string $escapeChar) : string
3674
    {
3675
        return preg_replace(
3676
            '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u',
3677
            addcslashes($escapeChar, '\\') . '$1',
3678
            $inputString
3679
        );
3680
    }
3681
3682
    protected function getLikeWildcardCharacters() : string
3683
    {
3684
        return '%_';
3685
    }
3686
}
3687