Completed
Pull Request — 2.10.x (#3936)
by Asmir
65:42
created

supportsNamedPrimaryConstraints()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
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[] $columns
155 67655
     *
156
     * @return string
157
     */
158
    protected function getPrimaryKeyAsConstraintSQL(array $columns, Index $index)
159
    {
160 60839
        $columnListSql = '';
161
        if ($index->getName() !== 'primary') {
162 60839
            $columnListSql = 'CONSTRAINT ' . $index->getQuotedName($this) . ' ';
163 60839
        }
164
165
        return $columnListSql . $this->getPrimaryKeyAsDefinitionSQL($columns, $index);
166
    }
167
168
    /**
169
     * @param mixed[] $columns
170 58230
     *
171
     * @return string
172 58230
     */
173
    protected function getPrimaryKeyAsDefinitionSQL(array $columns, Index $index)
174
    {
175
        $flags = '';
176
        if ($index->hasFlag('nonclustered')) {
177
            $flags .= ' NONCLUSTERED';
178
        }
179
180
        if ($index->hasFlag('clustered')) {
181
            $flags .= ' CLUSTERED';
182
        }
183
184
        return 'PRIMARY KEY' . ($flags ? $flags : '') . ' (' . implode(', ', array_unique(array_values($columns))) . ')';
185
    }
186
187
    public function __construct()
188
    {
189
    }
190
191
    /**
192
     * Sets the EventManager used by the Platform.
193
     *
194
     * @return void
195
     */
196
    public function setEventManager(EventManager $eventManager)
197
    {
198
        $this->_eventManager = $eventManager;
199
    }
200
201
    /**
202
     * Gets the EventManager used by the Platform.
203
     *
204
     * @return EventManager
205
     */
206
    public function getEventManager()
207
    {
208
        return $this->_eventManager;
209
    }
210
211
    /**
212
     * Returns the SQL snippet that declares a boolean column.
213
     *
214
     * @param mixed[] $columnDef
215
     *
216
     * @return string
217
     */
218
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
219
220
    /**
221
     * Returns the SQL snippet that declares a 4 byte integer column.
222
     *
223
     * @param mixed[] $columnDef
224
     *
225
     * @return string
226
     */
227
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
228
229
    /**
230
     * Returns the SQL snippet that declares an 8 byte integer column.
231
     *
232
     * @param mixed[] $columnDef
233 58308
     *
234
     * @return string
235 58308
     */
236
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
237 58308
238 58308
    /**
239 30122
     * Returns the SQL snippet that declares a 2 byte integer column.
240
     *
241
     * @param mixed[] $columnDef
242 58308
     *
243
     * @return string
244
     */
245
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
246
247
    /**
248
     * Returns the SQL snippet that declares common properties of an integer column.
249
     *
250
     * @param mixed[] $columnDef
251 60263
     *
252
     * @return string
253 60263
     */
254 56812
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
255
256
    /**
257 60263
     * Lazy load Doctrine Type Mappings.
258
     *
259 60263
     * @return void
260 58370
     */
261 60263
    abstract protected function initializeDoctrineTypeMappings();
262
263 60263
    /**
264
     * Initializes Doctrine Type Mappings with the platform defaults
265
     * and with all additional type mappings.
266
     *
267 60263
     * @return void
268
     */
269
    private function initializeAllDoctrineTypeMappings()
270
    {
271
        $this->initializeDoctrineTypeMappings();
272
273
        foreach (Type::getTypesMap() as $typeName => $className) {
274
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
275
                $this->doctrineTypeMapping[$dbType] = $typeName;
276
            }
277 56993
        }
278
    }
279 56993
280 56937
    /**
281
     * Returns the SQL snippet used to declare a VARCHAR column type.
282
     *
283 56993
     * @param mixed[] $field
284
     *
285 56993
     * @return string
286
     */
287 56993
    public function getVarcharTypeDeclarationSQL(array $field)
288 54817
    {
289 54557
        if (! isset($field['length'])) {
290 24
            $field['length'] = $this->getVarcharDefaultLength();
291 54557
        }
292 54557
293 54557
        $fixed = $field['fixed'] ?? false;
294
295
        $maxLength = $fixed
296 54817
            ? $this->getCharMaxLength()
297
            : $this->getVarcharMaxLength();
298
299 56969
        if ($field['length'] > $maxLength) {
300
            return $this->getClobTypeDeclarationSQL($field);
301
        }
302
303
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
304
    }
305
306
    /**
307
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
308
     *
309
     * @param mixed[] $field The column definition.
310
     *
311
     * @return string
312 56064
     */
313
    public function getBinaryTypeDeclarationSQL(array $field)
314 56064
    {
315 56064
        if (! isset($field['length'])) {
316
            $field['length'] = $this->getBinaryDefaultLength();
317 56064
        }
318
319
        $fixed = $field['fixed'] ?? false;
320
321
        $maxLength = $this->getBinaryMaxLength();
322
323
        if ($field['length'] > $maxLength) {
324
            if ($maxLength > 0) {
325
                @trigger_error(sprintf(
326
                    'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.',
327
                    $field['length'],
328
                    $maxLength
329
                ), E_USER_DEPRECATED);
330 54418
            }
331
332 54418
            return $this->getBlobTypeDeclarationSQL($field);
333
        }
334
335
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
336
    }
337
338
    /**
339
     * Returns the SQL snippet to declare a GUID/UUID field.
340
     *
341
     * By default this maps directly to a CHAR(36) and only maps to more
342
     * special datatypes when the underlying databases support this datatype.
343
     *
344
     * @param mixed[] $field
345
     *
346
     * @return string
347
     */
348
    public function getGuidTypeDeclarationSQL(array $field)
349
    {
350
        $field['length'] = 36;
351
        $field['fixed']  = true;
352
353
        return $this->getVarcharTypeDeclarationSQL($field);
354
    }
355
356
    /**
357
     * Returns the SQL snippet to declare a JSON field.
358
     *
359
     * By default this maps directly to a CLOB and only maps to more
360
     * special datatypes when the underlying databases support this datatype.
361
     *
362
     * @param mixed[] $field
363
     *
364
     * @return string
365
     */
366
    public function getJsonTypeDeclarationSQL(array $field)
367
    {
368
        return $this->getClobTypeDeclarationSQL($field);
369
    }
370
371
    /**
372
     * @param int  $length
373
     * @param bool $fixed
374
     *
375
     * @return string
376
     *
377
     * @throws DBALException If not supported on this platform.
378
     */
379
    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

379
    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...
380
    {
381
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
382
    }
383
384
    /**
385
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
386
     *
387
     * @param int  $length The length of the column.
388
     * @param bool $fixed  Whether the column length is fixed.
389
     *
390
     * @return string
391
     *
392
     * @throws DBALException If not supported on this platform.
393
     */
394
    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

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

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

919
    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...
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

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

1090
    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

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

1348
    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 $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

1348
    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 $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

1348
    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...
1349
    {
1350
        throw DBALException::notSupported(__METHOD__);
1351
    }
1352
1353
    /**
1354
     * Returns the SQL bit AND comparison expression.
1355
     *
1356
     * @param string $value1
1357
     * @param string $value2
1358
     *
1359
     * @return string
1360 48452
     */
1361
    public function getBitAndComparisonExpression($value1, $value2)
1362 48452
    {
1363
        return '(' . $value1 . ' & ' . $value2 . ')';
1364
    }
1365
1366
    /**
1367
     * Returns the SQL bit OR comparison expression.
1368
     *
1369
     * @param string $value1
1370
     * @param string $value2
1371
     *
1372
     * @return string
1373
     */
1374
    public function getBitOrComparisonExpression($value1, $value2)
1375
    {
1376
        return '(' . $value1 . ' | ' . $value2 . ')';
1377
    }
1378
1379
    /**
1380
     * Returns the FOR UPDATE expression.
1381
     *
1382
     * @return string
1383
     */
1384
    public function getForUpdateSQL()
1385 53298
    {
1386
        return 'FOR UPDATE';
1387 53298
    }
1388
1389
    /**
1390
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1391
     *
1392
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1393
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1394
     *                             be appended to the FROM clause.
1395
     *
1396
     * @return string
1397 47094
     */
1398
    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

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

1785
    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...
1786 53708
    {
1787 53708
        throw DBALException::notSupported(__METHOD__);
1788
    }
1789 53708
1790 53708
    /**
1791
     * Returns the SQL to change a sequence on this platform.
1792 53762
     *
1793
     * @return string
1794 53762
     *
1795
     * @throws DBALException If not supported on this platform.
1796
     */
1797
    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

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

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

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

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

2967
    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...
2968
    {
2969
        throw DBALException::notSupported(__METHOD__);
2970
    }
2971
2972
    /**
2973
     * @param string $sequenceName
2974
     *
2975
     * @return string
2976
     *
2977
     * @throws DBALException If not supported on this platform.
2978
     */
2979
    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

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

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