Passed
Pull Request — master (#2412)
by Benoît
13:20
created

AbstractPlatform::getLikeWildcardCharacters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Platforms;
21
22
use Doctrine\Common\EventManager;
23
use Doctrine\DBAL\DBALException;
24
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
25
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
26
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
27
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
28
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
29
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
30
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
31
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
32
use Doctrine\DBAL\Events;
33
use Doctrine\DBAL\Schema\Column;
34
use Doctrine\DBAL\Schema\ColumnDiff;
35
use Doctrine\DBAL\Schema\Constraint;
36
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
37
use Doctrine\DBAL\Schema\Identifier;
38
use Doctrine\DBAL\Schema\Index;
39
use Doctrine\DBAL\Schema\Sequence;
40
use Doctrine\DBAL\Schema\Table;
41
use Doctrine\DBAL\Schema\TableDiff;
42
use Doctrine\DBAL\TransactionIsolationLevel;
43
use Doctrine\DBAL\Types;
44
use Doctrine\DBAL\Types\Type;
45
use const E_USER_DEPRECATED;
46
use function addcslashes;
47
use function array_map;
48
use function array_merge;
49
use function array_unique;
50
use function array_values;
51
use function count;
52
use function explode;
53
use function func_get_arg;
54
use function func_get_args;
55
use function func_num_args;
56
use function get_class;
57
use function implode;
58
use function in_array;
59
use function is_array;
60
use function is_bool;
61
use function is_int;
62
use function is_string;
63
use function join;
64
use function preg_quote;
65
use function preg_replace;
66
use function sprintf;
67
use function str_replace;
68
use function strlen;
69
use function strpos;
70
use function strtolower;
71
use function strtoupper;
72
use function trigger_error;
73
74
/**
75
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
76
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
77
 * They are a passive source of information.
78
 *
79
 * @link   www.doctrine-project.org
80
 * @since  2.0
81
 * @author Guilherme Blanco <[email protected]>
82
 * @author Jonathan Wage <[email protected]>
83
 * @author Roman Borschel <[email protected]>
84
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
85
 * @author Benjamin Eberlei <[email protected]>
86
 * @todo   Remove any unnecessary methods.
87
 */
88
abstract class AbstractPlatform
89
{
90
    /**
91
     * @var int
92
     */
93
    const CREATE_INDEXES = 1;
94
95
    /**
96
     * @var int
97
     */
98
    const CREATE_FOREIGNKEYS = 2;
99
100
    /**
101
     * @deprecated Use DateIntervalUnit::INTERVAL_UNIT_SECOND.
102
     */
103
    public const DATE_INTERVAL_UNIT_SECOND = DateIntervalUnit::SECOND;
104
105
    /**
106
     * @deprecated Use DateIntervalUnit::MINUTE.
107
     */
108
    public const DATE_INTERVAL_UNIT_MINUTE = DateIntervalUnit::MINUTE;
109
110
    /**
111
     * @deprecated Use DateIntervalUnit::HOUR.
112
     */
113
    public const DATE_INTERVAL_UNIT_HOUR = DateIntervalUnit::HOUR;
114
115
    /**
116
     * @deprecated Use DateIntervalUnit::DAY.
117
     */
118
    public const DATE_INTERVAL_UNIT_DAY = DateIntervalUnit::DAY;
119
120
    /**
121
     * @deprecated Use DateIntervalUnit::WEEK.
122
     */
123
    public const DATE_INTERVAL_UNIT_WEEK = DateIntervalUnit::WEEK;
124
125
    /**
126
     * @deprecated Use DateIntervalUnit::MONTH.
127
     */
128
    public const DATE_INTERVAL_UNIT_MONTH = DateIntervalUnit::MONTH;
129
130
    /**
131
     * @deprecated Use DateIntervalUnit::QUARTER.
132
     */
133
    public const DATE_INTERVAL_UNIT_QUARTER = DateIntervalUnit::QUARTER;
134
135
    /**
136
     * @deprecated Use DateIntervalUnit::QUARTER.
137
     */
138
    public const DATE_INTERVAL_UNIT_YEAR = DateIntervalUnit::YEAR;
139
140
    /**
141
     * @var int
142
     *
143
     * @deprecated Use TrimMode::UNSPECIFIED.
144
     */
145
    public const TRIM_UNSPECIFIED = TrimMode::UNSPECIFIED;
146
147
    /**
148
     * @var int
149
     *
150
     * @deprecated Use TrimMode::LEADING.
151
     */
152
    public const TRIM_LEADING = TrimMode::LEADING;
153
154
    /**
155
     * @var int
156
     *
157
     * @deprecated Use TrimMode::TRAILING.
158
     */
159
    public const TRIM_TRAILING = TrimMode::TRAILING;
160
161
    /**
162
     * @var int
163
     *
164
     * @deprecated Use TrimMode::BOTH.
165
     */
166
    public const TRIM_BOTH = TrimMode::BOTH;
167
168
    /**
169
     * @var array|null
170
     */
171
    protected $doctrineTypeMapping = null;
172
173
    /**
174
     * Contains a list of all columns that should generate parseable column comments for type-detection
175
     * in reverse engineering scenarios.
176
     *
177
     * @var array|null
178
     */
179
    protected $doctrineTypeComments = null;
180
181
    /**
182
     * @var \Doctrine\Common\EventManager
183
     */
184
    protected $_eventManager;
185
186
    /**
187
     * Holds the KeywordList instance for the current platform.
188
     *
189
     * @var \Doctrine\DBAL\Platforms\Keywords\KeywordList
190
     */
191
    protected $_keywords;
192
193
    /**
194
     * Constructor.
195
     */
196 66937
    public function __construct()
197
    {
198 66937
    }
199
200
    /**
201
     * Sets the EventManager used by the Platform.
202
     *
203
     * @param \Doctrine\Common\EventManager $eventManager
204
     */
205 1710
    public function setEventManager(EventManager $eventManager)
206
    {
207 1710
        $this->_eventManager = $eventManager;
208 1710
    }
209
210
    /**
211
     * Gets the EventManager used by the Platform.
212
     *
213
     * @return \Doctrine\Common\EventManager
214
     */
215 1030
    public function getEventManager()
216
    {
217 1030
        return $this->_eventManager;
218
    }
219
220
    /**
221
     * Returns the SQL snippet that declares a boolean column.
222
     *
223
     * @param array $columnDef
224
     *
225
     * @return string
226
     */
227
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
228
229
    /**
230
     * Returns the SQL snippet that declares a 4 byte integer column.
231
     *
232
     * @param array $columnDef
233
     *
234
     * @return string
235
     */
236
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
237
238
    /**
239
     * Returns the SQL snippet that declares an 8 byte integer column.
240
     *
241
     * @param array $columnDef
242
     *
243
     * @return string
244
     */
245
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
246
247
    /**
248
     * Returns the SQL snippet that declares a 2 byte integer column.
249
     *
250
     * @param array $columnDef
251
     *
252
     * @return string
253
     */
254
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
255
256
    /**
257
     * Returns the SQL snippet that declares common properties of an integer column.
258
     *
259
     * @param array $columnDef
260
     *
261
     * @return string
262
     */
263
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
264
265
    /**
266
     * Lazy load Doctrine Type Mappings.
267
     *
268
     * @return void
269
     */
270
    abstract protected function initializeDoctrineTypeMappings();
271
272
    /**
273
     * Initializes Doctrine Type Mappings with the platform defaults
274
     * and with all additional type mappings.
275
     *
276
     * @return void
277
     */
278 1881
    private function initializeAllDoctrineTypeMappings()
279
    {
280 1881
        $this->initializeDoctrineTypeMappings();
281
282 1881
        foreach (Type::getTypesMap() as $typeName => $className) {
283 1881
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
284 1881
                $this->doctrineTypeMapping[$dbType] = $typeName;
285
            }
286
        }
287 1881
    }
288
289
    /**
290
     * Returns the SQL snippet used to declare a VARCHAR column type.
291
     *
292
     * @param array $field
293
     *
294
     * @return string
295
     */
296 6621
    public function getVarcharTypeDeclarationSQL(array $field)
297
    {
298 6621
        if ( !isset($field['length'])) {
299 1571
            $field['length'] = $this->getVarcharDefaultLength();
300
        }
301
302 6621
        $fixed = $field['fixed'] ?? false;
303
304 6621
        $maxLength = $fixed
305 939
            ? $this->getCharMaxLength()
306 6621
            : $this->getVarcharMaxLength();
307
308 6621
        if ($field['length'] > $maxLength) {
309
            return $this->getClobTypeDeclarationSQL($field);
310
        }
311
312 6621
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
313
    }
314
315
    /**
316
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
317
     *
318
     * @param array $field The column definition.
319
     *
320
     * @return string
321
     */
322 607
    public function getBinaryTypeDeclarationSQL(array $field)
323
    {
324 607
        if ( ! isset($field['length'])) {
325 360
            $field['length'] = $this->getBinaryDefaultLength();
326
        }
327
328 607
        $fixed = $field['fixed'] ?? false;
329
330 607
        $maxLength = $this->getBinaryMaxLength();
331
332 607
        if ($field['length'] > $maxLength) {
333 349
            if ($maxLength > 0) {
334 228
                @trigger_error(sprintf(
335 228
                    'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.',
336 228
                    $field['length'],
337 228
                    $maxLength
338 228
                ), E_USER_DEPRECATED);
339
            }
340
341 349
            return $this->getBlobTypeDeclarationSQL($field);
342
        }
343
344 372
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
345
    }
346
347
    /**
348
     * Returns the SQL snippet to declare a GUID/UUID field.
349
     *
350
     * By default this maps directly to a CHAR(36) and only maps to more
351
     * special datatypes when the underlying databases support this datatype.
352
     *
353
     * @param array $field
354
     *
355
     * @return string
356
     */
357 122
    public function getGuidTypeDeclarationSQL(array $field)
358
    {
359 122
        $field['length'] = 36;
360 122
        $field['fixed']  = true;
361
362 122
        return $this->getVarcharTypeDeclarationSQL($field);
363
    }
364
365
    /**
366
     * Returns the SQL snippet to declare a JSON field.
367
     *
368
     * By default this maps directly to a CLOB and only maps to more
369
     * special datatypes when the underlying databases support this datatype.
370
     *
371
     * @param array $field
372
     *
373
     * @return string
374
     */
375 404
    public function getJsonTypeDeclarationSQL(array $field)
376
    {
377 404
        return $this->getClobTypeDeclarationSQL($field);
378
    }
379
380
    /**
381
     * @param int  $length
382
     * @param bool $fixed
383
     *
384
     * @return string
385
     *
386
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
387
     */
388
    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

388
    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...
389
    {
390
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
391
    }
392
393
    /**
394
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
395
     *
396
     * @param int  $length The length of the column.
397
     * @param bool $fixed  Whether the column length is fixed.
398
     *
399
     * @return string
400
     *
401
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
402
     */
403
    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

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

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

924
    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

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

1095
    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

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

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

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

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

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

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

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

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

1762
    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...
1763
    {
1764
        throw DBALException::notSupported(__METHOD__);
1765
    }
1766
1767
    /**
1768
     * Returns the SQL to change a sequence on this platform.
1769
     *
1770
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1771
     *
1772
     * @return string
1773
     *
1774
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1775
     */
1776
    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

1776
    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...
1777
    {
1778
        throw DBALException::notSupported(__METHOD__);
1779
    }
1780
1781
    /**
1782
     * Returns the SQL to create a constraint on a table on this platform.
1783
     *
1784
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1785
     * @param \Doctrine\DBAL\Schema\Table|string $table
1786
     *
1787
     * @return string
1788
     *
1789
     * @throws \InvalidArgumentException
1790
     */
1791 328
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1792
    {
1793 328
        if ($table instanceof Table) {
1794
            $table = $table->getQuotedName($this);
1795
        }
1796
1797 328
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1798
1799 328
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1800
1801 328
        $referencesClause = '';
1802 328
        if ($constraint instanceof Index) {
1803 328
            if ($constraint->isPrimary()) {
1804 328
                $query .= ' PRIMARY KEY';
1805 247
            } elseif ($constraint->isUnique()) {
1806 247
                $query .= ' UNIQUE';
1807
            } else {
1808
                throw new \InvalidArgumentException(
1809 328
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1810
                );
1811
            }
1812 247
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1813 247
            $query .= ' FOREIGN KEY';
1814
1815 247
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1816 247
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1817
        }
1818 328
        $query .= ' '.$columnList.$referencesClause;
1819
1820 328
        return $query;
1821
    }
1822
1823
    /**
1824
     * Returns the SQL to create an index on a table on this platform.
1825
     *
1826
     * @param \Doctrine\DBAL\Schema\Index        $index
1827
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1828
     *
1829
     * @return string
1830
     *
1831
     * @throws \InvalidArgumentException
1832
     */
1833 3034
    public function getCreateIndexSQL(Index $index, $table)
1834
    {
1835 3034
        if ($table instanceof Table) {
1836 19
            $table = $table->getQuotedName($this);
1837
        }
1838 3034
        $name = $index->getQuotedName($this);
1839 3034
        $columns = $index->getColumns();
1840
1841 3034
        if (count($columns) == 0) {
1842
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1843
        }
1844
1845 3034
        if ($index->isPrimary()) {
1846 399
            return $this->getCreatePrimaryKeySQL($index, $table);
1847
        }
1848
1849 2673
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1850 2673
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index);
1851
1852 2673
        return $query;
1853
    }
1854
1855
    /**
1856
     * Adds condition for partial index.
1857
     *
1858
     * @param \Doctrine\DBAL\Schema\Index $index
1859
     *
1860
     * @return string
1861
     */
1862 3680
    protected function getPartialIndexSQL(Index $index)
1863
    {
1864 3680
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1865 101
            return  ' WHERE ' . $index->getOption('where');
1866
        }
1867
1868 3579
        return '';
1869
    }
1870
1871
    /**
1872
     * Adds additional flags for index generation.
1873
     *
1874
     * @param \Doctrine\DBAL\Schema\Index $index
1875
     *
1876
     * @return string
1877
     */
1878 1314
    protected function getCreateIndexSQLFlags(Index $index)
1879
    {
1880 1314
        return $index->isUnique() ? 'UNIQUE ' : '';
1881
    }
1882
1883
    /**
1884
     * Returns the SQL to create an unnamed primary key constraint.
1885
     *
1886
     * @param \Doctrine\DBAL\Schema\Index        $index
1887
     * @param \Doctrine\DBAL\Schema\Table|string $table
1888
     *
1889
     * @return string
1890
     */
1891 323
    public function getCreatePrimaryKeySQL(Index $index, $table)
1892
    {
1893 323
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')';
0 ignored issues
show
Bug introduced by
Are you sure $table of type Doctrine\DBAL\Schema\Table|string 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

1893
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')';
Loading history...
1894
    }
1895
1896
    /**
1897
     * Returns the SQL to create a named schema.
1898
     *
1899
     * @param string $schemaName
1900
     *
1901
     * @return string
1902
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1903
     */
1904 190
    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

1904
    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...
1905
    {
1906 190
        throw DBALException::notSupported(__METHOD__);
1907
    }
1908
1909
    /**
1910
     * Quotes a string so that it can be safely used as a table or column name,
1911
     * even if it is a reserved word of the platform. This also detects identifier
1912
     * chains separated by dot and quotes them independently.
1913
     *
1914
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1915
     * you SHOULD use them. In general, they end up causing way more
1916
     * problems than they solve.
1917
     *
1918
     * @param string $str The identifier name to be quoted.
1919
     *
1920
     * @return string The quoted identifier string.
1921
     */
1922 7570
    public function quoteIdentifier($str)
1923
    {
1924 7570
        if (strpos($str, ".") !== false) {
1925 372
            $parts = array_map([$this, "quoteSingleIdentifier"], explode(".", $str));
1926
1927 372
            return implode(".", $parts);
1928
        }
1929
1930 7570
        return $this->quoteSingleIdentifier($str);
1931
    }
1932
1933
    /**
1934
     * Quotes a single identifier (no dot chain separation).
1935
     *
1936
     * @param string $str The identifier name to be quoted.
1937
     *
1938
     * @return string The quoted identifier string.
1939
     */
1940 7030
    public function quoteSingleIdentifier($str)
1941
    {
1942 7030
        $c = $this->getIdentifierQuoteCharacter();
1943
1944 7030
        return $c . str_replace($c, $c.$c, $str) . $c;
1945
    }
1946
1947
    /**
1948
     * Returns the SQL to create a new foreign key.
1949
     *
1950
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key constraint.
1951
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
1952
     *
1953
     * @return string
1954
     */
1955 1695
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1956
    {
1957 1695
        if ($table instanceof Table) {
1958 19
            $table = $table->getQuotedName($this);
1959
        }
1960
1961 1695
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1962
1963 1695
        return $query;
1964
    }
1965
1966
    /**
1967
     * Gets the SQL statements for altering an existing table.
1968
     *
1969
     * This method returns an array of SQL statements, since some platforms need several statements.
1970
     *
1971
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1972
     *
1973
     * @return array
1974
     *
1975
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1976
     */
1977
    public function getAlterTableSQL(TableDiff $diff)
1978
    {
1979
        throw DBALException::notSupported(__METHOD__);
1980
    }
1981
1982
    /**
1983
     * @param \Doctrine\DBAL\Schema\Column    $column
1984
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1985
     * @param array                           $columnSql
1986
     *
1987
     * @return bool
1988
     */
1989 1885
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
1990
    {
1991 1885
        if (null === $this->_eventManager) {
1992 1520
            return false;
1993
        }
1994
1995 365
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1996 23
            return false;
1997
        }
1998
1999 342
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
2000 342
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
2001
2002 342
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2003
2004 342
        return $eventArgs->isDefaultPrevented();
2005
    }
2006
2007
    /**
2008
     * @param \Doctrine\DBAL\Schema\Column    $column
2009
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2010
     * @param array                           $columnSql
2011
     *
2012
     * @return bool
2013
     */
2014 1450
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
2015
    {
2016 1450
        if (null === $this->_eventManager) {
2017 1083
            return false;
2018
        }
2019
2020 367
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
2021 25
            return false;
2022
        }
2023
2024 342
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
2025 342
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
2026
2027 342
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2028
2029 342
        return $eventArgs->isDefaultPrevented();
2030
    }
2031
2032
    /**
2033
     * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff
2034
     * @param \Doctrine\DBAL\Schema\TableDiff  $diff
2035
     * @param array                            $columnSql
2036
     *
2037
     * @return bool
2038
     */
2039 3664
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
2040
    {
2041 3664
        if (null === $this->_eventManager) {
2042 3059
            return false;
2043
        }
2044
2045 605
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
2046 263
            return false;
2047
        }
2048
2049 342
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
2050 342
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
2051
2052 342
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2053
2054 342
        return $eventArgs->isDefaultPrevented();
2055
    }
2056
2057
    /**
2058
     * @param string                          $oldColumnName
2059
     * @param \Doctrine\DBAL\Schema\Column    $column
2060
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2061
     * @param array                           $columnSql
2062
     *
2063
     * @return bool
2064
     */
2065 1466
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
2066
    {
2067 1466
        if (null === $this->_eventManager) {
2068 1102
            return false;
2069
        }
2070
2071 364
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2072 22
            return false;
2073
        }
2074
2075 342
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2076 342
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2077
2078 342
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2079
2080 342
        return $eventArgs->isDefaultPrevented();
2081
    }
2082
2083
    /**
2084
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2085
     * @param array                           $sql
2086
     *
2087
     * @return bool
2088
     */
2089 6963
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
2090
    {
2091 6963
        if (null === $this->_eventManager) {
2092 6270
            return false;
2093
        }
2094
2095 693
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2096 351
            return false;
2097
        }
2098
2099 342
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2100 342
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2101
2102 342
        $sql = array_merge($sql, $eventArgs->getSql());
2103
2104 342
        return $eventArgs->isDefaultPrevented();
2105
    }
2106
2107
    /**
2108
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2109
     *
2110
     * @return array
2111
     */
2112 6697
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2113
    {
2114 6697
        $tableName = $diff->getName($this)->getQuotedName($this);
2115
2116 6697
        $sql = [];
2117 6697
        if ($this->supportsForeignKeyConstraints()) {
2118 6697
            foreach ($diff->removedForeignKeys as $foreignKey) {
2119 493
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2120
            }
2121 6697
            foreach ($diff->changedForeignKeys as $foreignKey) {
2122 380
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2123
            }
2124
        }
2125
2126 6697
        foreach ($diff->removedIndexes as $index) {
2127 243
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2128
        }
2129 6697
        foreach ($diff->changedIndexes as $index) {
2130 340
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2131
        }
2132
2133 6697
        return $sql;
2134
    }
2135
2136
    /**
2137
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2138
     *
2139
     * @return array
2140
     */
2141 6697
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2142
    {
2143 6697
        $tableName = (false !== $diff->newName)
2144 649
            ? $diff->getNewName()->getQuotedName($this)
2145 6697
            : $diff->getName($this)->getQuotedName($this);
2146
2147 6697
        $sql = [];
2148
2149 6697
        if ($this->supportsForeignKeyConstraints()) {
2150 6697
            foreach ($diff->addedForeignKeys as $foreignKey) {
2151 416
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2152
            }
2153
2154 6697
            foreach ($diff->changedForeignKeys as $foreignKey) {
2155 380
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2156
            }
2157
        }
2158
2159 6697
        foreach ($diff->addedIndexes as $index) {
2160 75
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2161
        }
2162
2163 6697
        foreach ($diff->changedIndexes as $index) {
2164 340
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2165
        }
2166
2167 6697
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2168 1651
            $oldIndexName = new Identifier($oldIndexName);
2169 1651
            $sql          = array_merge(
2170 1651
                $sql,
2171 1651
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2172
            );
2173
        }
2174
2175 6697
        return $sql;
2176
    }
2177
2178
    /**
2179
     * Returns the SQL for renaming an index on a table.
2180
     *
2181
     * @param string                      $oldIndexName The name of the index to rename from.
2182
     * @param \Doctrine\DBAL\Schema\Index $index        The definition of the index to rename to.
2183
     * @param string                      $tableName    The table to rename the given index on.
2184
     *
2185
     * @return array The sequence of SQL statements for renaming the given index.
2186
     */
2187 202
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2188
    {
2189
        return [
2190 202
            $this->getDropIndexSQL($oldIndexName, $tableName),
2191 202
            $this->getCreateIndexSQL($index, $tableName)
2192
        ];
2193
    }
2194
2195
    /**
2196
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2197
     *
2198
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2199
     *
2200
     * @return array
2201
     */
2202
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2203
    {
2204
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2205
    }
2206
2207
    /**
2208
     * Gets declaration of a number of fields in bulk.
2209
     *
2210
     * @param array $fields A multidimensional associative array.
2211
     *                      The first dimension determines the field name, while the second
2212
     *                      dimension is keyed with the name of the properties
2213
     *                      of the field being declared as array indexes. Currently, the types
2214
     *                      of supported field properties are as follows:
2215
     *
2216
     *      length
2217
     *          Integer value that determines the maximum length of the text
2218
     *          field. If this argument is missing the field should be
2219
     *          declared to have the longest length allowed by the DBMS.
2220
     *
2221
     *      default
2222
     *          Text value to be used as default for this field.
2223
     *
2224
     *      notnull
2225
     *          Boolean flag that indicates whether this field is constrained
2226
     *          to not be set to null.
2227
     *      charset
2228
     *          Text value with the default CHARACTER SET for this field.
2229
     *      collation
2230
     *          Text value with the default COLLATION for this field.
2231
     *      unique
2232
     *          unique constraint
2233
     *
2234
     * @return string
2235
     */
2236 7887
    public function getColumnDeclarationListSQL(array $fields)
2237
    {
2238 7887
        $queryFields = [];
2239
2240 7887
        foreach ($fields as $fieldName => $field) {
2241 7887
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2242
        }
2243
2244 7887
        return implode(', ', $queryFields);
2245
    }
2246
2247
    /**
2248
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2249
     * field to be used in statements like CREATE TABLE.
2250
     *
2251
     * @param string $name  The name the field to be declared.
2252
     * @param array  $field An associative array with the name of the properties
2253
     *                      of the field being declared as array indexes. Currently, the types
2254
     *                      of supported field properties are as follows:
2255
     *
2256
     *      length
2257
     *          Integer value that determines the maximum length of the text
2258
     *          field. If this argument is missing the field should be
2259
     *          declared to have the longest length allowed by the DBMS.
2260
     *
2261
     *      default
2262
     *          Text value to be used as default for this field.
2263
     *
2264
     *      notnull
2265
     *          Boolean flag that indicates whether this field is constrained
2266
     *          to not be set to null.
2267
     *      charset
2268
     *          Text value with the default CHARACTER SET for this field.
2269
     *      collation
2270
     *          Text value with the default COLLATION for this field.
2271
     *      unique
2272
     *          unique constraint
2273
     *      check
2274
     *          column check constraint
2275
     *      columnDefinition
2276
     *          a string that defines the complete column
2277
     *
2278
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2279
     */
2280 8350
    public function getColumnDeclarationSQL($name, array $field)
2281
    {
2282 8350
        if (isset($field['columnDefinition'])) {
2283 275
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2284
        } else {
2285 8084
            $default = $this->getDefaultValueDeclarationSQL($field);
2286
2287 8084
            $charset = (isset($field['charset']) && $field['charset']) ?
2288 8084
                ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2289
2290 8084
            $collation = (isset($field['collation']) && $field['collation']) ?
2291 8084
                ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2292
2293 8084
            $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
2294
2295 8084
            $unique = (isset($field['unique']) && $field['unique']) ?
2296 8084
                ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2297
2298 8084
            $check = (isset($field['check']) && $field['check']) ?
2299 8084
                ' ' . $field['check'] : '';
2300
2301 8084
            $typeDecl = $field['type']->getSQLDeclaration($field, $this);
2302 8084
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2303
2304 8084
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2305 699
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2306
            }
2307
        }
2308
2309 8350
        return $name . ' ' . $columnDef;
2310
    }
2311
2312
    /**
2313
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2314
     *
2315
     * @param array $columnDef
2316
     *
2317
     * @return string
2318
     */
2319 2551
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2320
    {
2321 2551
        $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
2322 2551
            ? 10 : $columnDef['precision'];
2323 2551
        $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
2324 2551
            ? 0 : $columnDef['scale'];
2325
2326 2551
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2327
    }
2328
2329
    /**
2330
     * Obtains DBMS specific SQL code portion needed to set a default value
2331
     * declaration to be used in statements like CREATE TABLE.
2332
     *
2333
     * @param array $field The field definition array.
2334
     *
2335
     * @return string DBMS specific SQL code portion needed to set a default value.
2336
     */
2337 9187
    public function getDefaultValueDeclarationSQL($field)
2338
    {
2339 9187
        if ( ! isset($field['default'])) {
2340 7910
            return empty($field['notnull']) ? ' DEFAULT NULL' : '';
2341
        }
2342
2343 1720
        $default = $field['default'];
2344
2345 1720
        if ( ! isset($field['type'])) {
2346
            return " DEFAULT '" . $default . "'";
2347
        }
2348
2349 1720
        $type = $field['type'];
2350
2351 1720
        if ($type instanceof Types\PhpIntegerMappingType) {
2352 469
            return ' DEFAULT ' . $default;
2353
        }
2354
2355 1299
        if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
2356 303
            return ' DEFAULT ' . $this->getCurrentTimestampSQL();
2357
        }
2358
2359 1006
        if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
2360 2
            return ' DEFAULT ' . $this->getCurrentTimeSQL();
2361
        }
2362
2363 1006
        if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
2364 287
            return ' DEFAULT ' . $this->getCurrentDateSQL();
2365
        }
2366
2367 719
        if ($type instanceof Types\BooleanType) {
2368 291
            return " DEFAULT '" . $this->convertBooleans($default) . "'";
2369
        }
2370
2371 713
        return " DEFAULT '" . $default . "'";
2372
    }
2373
2374
    /**
2375
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2376
     * declaration to be used in statements like CREATE TABLE.
2377
     *
2378
     * @param array $definition The check definition.
2379
     *
2380
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2381
     */
2382 2849
    public function getCheckDeclarationSQL(array $definition)
2383
    {
2384 2849
        $constraints = [];
2385 2849
        foreach ($definition as $field => $def) {
2386 2849
            if (is_string($def)) {
2387
                $constraints[] = 'CHECK (' . $def . ')';
2388
            } else {
2389 2849
                if (isset($def['min'])) {
2390 95
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2391
                }
2392
2393 2849
                if (isset($def['max'])) {
2394 2849
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2395
                }
2396
            }
2397
        }
2398
2399 2849
        return implode(', ', $constraints);
2400
    }
2401
2402
    /**
2403
     * Obtains DBMS specific SQL code portion needed to set a unique
2404
     * constraint declaration to be used in statements like CREATE TABLE.
2405
     *
2406
     * @param string                      $name  The name of the unique constraint.
2407
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2408
     *
2409
     * @return string DBMS specific SQL code portion needed to set a constraint.
2410
     *
2411
     * @throws \InvalidArgumentException
2412
     */
2413 532
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
2414
    {
2415 532
        $columns = $index->getColumns();
2416 532
        $name = new Identifier($name);
2417
2418 532
        if (count($columns) === 0) {
2419
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2420
        }
2421
2422 532
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2423 532
            . $this->getIndexFieldDeclarationListSQL($index)
2424 532
            . ')' . $this->getPartialIndexSQL($index);
2425
    }
2426
2427
    /**
2428
     * Obtains DBMS specific SQL code portion needed to set an index
2429
     * declaration to be used in statements like CREATE TABLE.
2430
     *
2431
     * @param string                      $name  The name of the index.
2432
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2433
     *
2434
     * @return string DBMS specific SQL code portion needed to set an index.
2435
     *
2436
     * @throws \InvalidArgumentException
2437
     */
2438 1010
    public function getIndexDeclarationSQL($name, Index $index)
2439
    {
2440 1010
        $columns = $index->getColumns();
2441 1010
        $name = new Identifier($name);
2442
2443 1010
        if (count($columns) === 0) {
2444
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2445
        }
2446
2447 1010
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2448 1010
            . $this->getIndexFieldDeclarationListSQL($index)
2449 1010
            . ')' . $this->getPartialIndexSQL($index);
2450
    }
2451
2452
    /**
2453
     * Obtains SQL code portion needed to create a custom column,
2454
     * e.g. when a field has the "columnDefinition" keyword.
2455
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2456
     *
2457
     * @param array $columnDef
2458
     *
2459
     * @return string
2460
     */
2461 351
    public function getCustomTypeDeclarationSQL(array $columnDef)
2462
    {
2463 351
        return $columnDef['columnDefinition'];
2464
    }
2465
2466
    /**
2467
     * Obtains DBMS specific SQL code portion needed to set an index
2468
     * declaration to be used in statements like CREATE TABLE.
2469
     *
2470
     * @param array[mixed]|Index $columnsOrIndex
0 ignored issues
show
Documentation Bug introduced by
The doc comment array[mixed]|Index at position 1 could not be parsed: Expected ']' at position 1, but found '['.
Loading history...
2471
     *
2472
     * @return string
2473
     */
2474 3593
    public function getIndexFieldDeclarationListSQL($columnsOrIndex)
2475
    {
2476 3593
        if ($columnsOrIndex instanceof Index) {
2477 2757
            return implode(', ', $columnsOrIndex->getQuotedColumns($this));
2478
        }
2479
2480 950
        if (! is_array($columnsOrIndex)) {
2481
            throw new \InvalidArgumentException('Fields argument should be an Index or an array.');
2482
        }
2483
2484 950
        $ret = [];
2485
2486 950
        foreach ($columnsOrIndex as $column => $definition) {
2487 950
            if (is_array($definition)) {
2488
                $ret[] = $column;
2489
            } else {
2490 950
                $ret[] = $definition;
2491
            }
2492
        }
2493
2494 950
        return implode(', ', $ret);
2495
    }
2496
2497
    /**
2498
     * Returns the required SQL string that fits between CREATE ... TABLE
2499
     * to create the table as a temporary table.
2500
     *
2501
     * Should be overridden in driver classes to return the correct string for the
2502
     * specific database type.
2503
     *
2504
     * The default is to return the string "TEMPORARY" - this will result in a
2505
     * SQL error for any database that does not support temporary tables, or that
2506
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2507
     *
2508
     * @return string The string required to be placed between "CREATE" and "TABLE"
2509
     *                to generate a temporary table, if possible.
2510
     */
2511
    public function getTemporaryTableSQL()
2512
    {
2513
        return 'TEMPORARY';
2514
    }
2515
2516
    /**
2517
     * Some vendors require temporary table names to be qualified specially.
2518
     *
2519
     * @param string $tableName
2520
     *
2521
     * @return string
2522
     */
2523 28
    public function getTemporaryTableName($tableName)
2524
    {
2525 28
        return $tableName;
2526
    }
2527
2528
    /**
2529
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2530
     * of a field declaration to be used in statements like CREATE TABLE.
2531
     *
2532
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2533
     *
2534
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2535
     *                of a field declaration.
2536
     */
2537 2342
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2538
    {
2539 2342
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2540 2114
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2541
2542 2114
        return $sql;
2543
    }
2544
2545
    /**
2546
     * Returns the FOREIGN KEY query section dealing with non-standard options
2547
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2548
     *
2549
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key definition.
2550
     *
2551
     * @return string
2552
     */
2553 2026
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2554
    {
2555 2026
        $query = '';
2556 2026
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2557 76
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2558
        }
2559 2026
        if ($foreignKey->hasOption('onDelete')) {
2560 188
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2561
        }
2562
2563 2026
        return $query;
2564
    }
2565
2566
    /**
2567
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2568
     *
2569
     * @param string $action The foreign key referential action.
2570
     *
2571
     * @return string
2572
     *
2573
     * @throws \InvalidArgumentException if unknown referential action given
2574
     */
2575 2316
    public function getForeignKeyReferentialActionSQL($action)
2576
    {
2577 2316
        $upper = strtoupper($action);
2578 121
        switch ($upper) {
2579 2316
            case 'CASCADE':
2580 1564
            case 'SET NULL':
2581 1165
            case 'NO ACTION':
2582 918
            case 'RESTRICT':
2583 652
            case 'SET DEFAULT':
2584 1993
                return $upper;
2585
            default:
2586 323
                throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper);
2587
        }
2588
    }
2589
2590
    /**
2591
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2592
     * of a field declaration to be used in statements like CREATE TABLE.
2593
     *
2594
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2595
     *
2596
     * @return string
2597
     *
2598
     * @throws \InvalidArgumentException
2599
     */
2600 1582
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2601
    {
2602 1582
        $sql = '';
2603 1582
        if (strlen($foreignKey->getName())) {
2604 1316
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2605
        }
2606 1582
        $sql .= 'FOREIGN KEY (';
2607
2608 1582
        if (count($foreignKey->getLocalColumns()) === 0) {
2609
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
2610
        }
2611 1582
        if (count($foreignKey->getForeignColumns()) === 0) {
2612
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
2613
        }
2614 1582
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2615
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2616
        }
2617
2618 1582
        $sql .= implode(', ', $foreignKey->getQuotedLocalColumns($this))
2619 1582
            . ') REFERENCES '
2620 1582
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2621 1582
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2622
2623 1582
        return $sql;
2624
    }
2625
2626
    /**
2627
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2628
     * of a field declaration to be used in statements like CREATE TABLE.
2629
     *
2630
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2631
     *                of a field declaration.
2632
     */
2633
    public function getUniqueFieldDeclarationSQL()
2634
    {
2635
        return 'UNIQUE';
2636
    }
2637
2638
    /**
2639
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2640
     * of a field declaration to be used in statements like CREATE TABLE.
2641
     *
2642
     * @param string $charset The name of the charset.
2643
     *
2644
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2645
     *                of a field declaration.
2646
     */
2647
    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

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

2962
    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...
2963
    {
2964
        throw DBALException::notSupported(__METHOD__);
2965
    }
2966
2967
    /**
2968
     * @param string $sequenceName
2969
     *
2970
     * @return string
2971
     *
2972
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2973
     */
2974
    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

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

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