Passed
Pull Request — master (#3225)
by Šimon
12:57
created

AbstractPlatform::getCreateSchemaSQL()   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
c 0
b 0
f 0
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
cc 1
eloc 1
nc 1
nop 1
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 1022
    public function getEventManager()
216
    {
217 1022
        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 6613
    public function getVarcharTypeDeclarationSQL(array $field)
297
    {
298 6613
        if ( !isset($field['length'])) {
299 1571
            $field['length'] = $this->getVarcharDefaultLength();
300
        }
301
302 6613
        $fixed = $field['fixed'] ?? false;
303
304 6613
        $maxLength = $fixed
305 939
            ? $this->getCharMaxLength()
306 6613
            : $this->getVarcharMaxLength();
307
308 6613
        if ($field['length'] > $maxLength) {
309
            return $this->getClobTypeDeclarationSQL($field);
310
        }
311
312 6613
        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 2067
    public function getDoctrineTypeMapping($dbType)
471
    {
472 2067
        if ($this->doctrineTypeMapping === null) {
473 399
            $this->initializeAllDoctrineTypeMappings();
474
        }
475
476 2067
        $dbType = strtolower($dbType);
477
478 2067
        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 1725
        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 19335
    public function isCommentedDoctrineType(Type $doctrineType)
529
    {
530 19335
        if ($this->doctrineTypeComments === null) {
531 16345
            $this->initializeCommentedDoctrineTypes();
532
        }
533
534 19335
        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 10463
    protected function getColumnComment(Column $column)
573
    {
574 10463
        $comment = $column->getComment();
575
576 10463
        if ($this->isCommentedDoctrineType($column->getType())) {
577 811
            $comment .= $this->getDoctrineTypeComment($column->getType());
578
        }
579
580 10463
        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:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
840 144
                $expression = 'LEADING ';
841 144
                break;
842
843 405
            case TrimMode::TRAILING:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
844 144
                $expression = 'TRAILING ';
845 144
                break;
846
847 270
            case TrimMode::BOTH:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

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

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

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

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

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

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

2952
    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...
2953
    {
2954
        throw DBALException::notSupported(__METHOD__);
2955
    }
2956
2957
    /**
2958
     * @param string $sequenceName
2959
     *
2960
     * @return string
2961
     *
2962
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2963
     */
2964
    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

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

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