Completed
Push — master ( 89a52c...c0f6d4 )
by Marco
19s queued 13s
created

AbstractPlatform::getCosExpression()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 2
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)',
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
    public function getGuidExpression()
691
    {
692
        throw DBALException::notSupported(__METHOD__);
693
    }
694
695
    /**
696
     * Returns the SQL snippet to get the average value of a column.
697
     *
698
     * @param string $column The column to use.
699
     *
700
     * @return string Generated SQL including an AVG aggregate function.
701
     */
702
    public function getAvgExpression($column)
703
    {
704
        return 'AVG(' . $column . ')';
705
    }
706
707
    /**
708
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
709
     *
710
     * If a '*' is used instead of a column the number of selected rows is returned.
711
     *
712
     * @param string|integer $column The column to use.
713
     *
714
     * @return string Generated SQL including a COUNT aggregate function.
715
     */
716
    public function getCountExpression($column)
717
    {
718
        return 'COUNT(' . $column . ')';
719
    }
720
721
    /**
722
     * Returns the SQL snippet to get the highest value of a column.
723
     *
724
     * @param string $column The column to use.
725
     *
726
     * @return string Generated SQL including a MAX aggregate function.
727
     */
728
    public function getMaxExpression($column)
729
    {
730
        return 'MAX(' . $column . ')';
731
    }
732
733
    /**
734
     * Returns the SQL snippet to get the lowest value of a column.
735
     *
736
     * @param string $column The column to use.
737
     *
738
     * @return string Generated SQL including a MIN aggregate function.
739
     */
740
    public function getMinExpression($column)
741
    {
742
        return 'MIN(' . $column . ')';
743
    }
744
745
    /**
746
     * Returns the SQL snippet to get the total sum of a column.
747
     *
748
     * @param string $column The column to use.
749
     *
750
     * @return string Generated SQL including a SUM aggregate function.
751
     */
752
    public function getSumExpression($column)
753
    {
754
        return 'SUM(' . $column . ')';
755
    }
756
757
    // scalar functions
758
759
    /**
760
     * Returns the SQL snippet to get the md5 sum of a field.
761
     *
762
     * Note: Not SQL92, but common functionality.
763
     *
764
     * @param string $column
765
     *
766
     * @return string
767
     */
768
    public function getMd5Expression($column)
769
    {
770
        return 'MD5(' . $column . ')';
771
    }
772
773
    /**
774
     * Returns the SQL snippet to get the length of a text field.
775
     *
776
     * @param string $column
777
     *
778
     * @return string
779
     */
780
    public function getLengthExpression($column)
781
    {
782
        return 'LENGTH(' . $column . ')';
783
    }
784
785
    /**
786
     * Returns the SQL snippet to get the squared value of a column.
787
     *
788
     * @param string $column The column to use.
789
     *
790
     * @return string Generated SQL including an SQRT aggregate function.
791
     */
792
    public function getSqrtExpression($column)
793
    {
794
        return 'SQRT(' . $column . ')';
795
    }
796
797
    /**
798
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
799
     *
800
     * @param string $column
801
     * @param int    $decimals
802
     *
803
     * @return string
804
     */
805
    public function getRoundExpression($column, $decimals = 0)
806
    {
807
        return 'ROUND(' . $column . ', ' . $decimals . ')';
808
    }
809
810
    /**
811
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
812
     *
813
     * @param string $expression1
814
     * @param string $expression2
815
     *
816
     * @return string
817
     */
818
    public function getModExpression($expression1, $expression2)
819
    {
820
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
821
    }
822
823
    /**
824
     * Returns the SQL snippet to trim a string.
825
     *
826
     * @param string      $str  The expression to apply the trim to.
827
     * @param int         $mode The position of the trim (leading/trailing/both).
828
     * @param string|bool $char The char to trim, has to be quoted already. Defaults to space.
829
     *
830
     * @return string
831
     */
832 576
    public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false)
833
    {
834 576
        $expression = '';
835
836 36
        switch ($mode) {
837 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...
838 144
                $expression = 'LEADING ';
839 144
                break;
840
841 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...
842 144
                $expression = 'TRAILING ';
843 144
                break;
844
845 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...
846 144
                $expression = 'BOTH ';
847 144
                break;
848
        }
849
850 576
        if ($char !== false) {
851 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

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

922
    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

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

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

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

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

1351
    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

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

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

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

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

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

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

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

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

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

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

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

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

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

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