Passed
Pull Request — master (#3135)
by Michael
17:53
created

AbstractPlatform::getIndexDeclarationSQL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 7
cts 8
cp 0.875
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 2
crap 2.0078
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 function addcslashes;
46
use function array_map;
47
use function array_merge;
48
use function array_unique;
49
use function array_values;
50
use function count;
51
use function explode;
52
use function func_get_arg;
53
use function func_get_args;
54
use function func_num_args;
55
use function get_class;
56
use function implode;
57
use function in_array;
58
use function is_array;
59
use function is_bool;
60
use function is_int;
61
use function is_string;
62
use function join;
63
use function preg_quote;
64
use function preg_replace;
65
use function sprintf;
66
use function str_replace;
67
use function strlen;
68
use function strpos;
69
use function strtolower;
70
use function strtoupper;
71
72
/**
73
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
74
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
75
 * They are a passive source of information.
76
 *
77
 * @link   www.doctrine-project.org
78
 * @since  2.0
79
 * @author Guilherme Blanco <[email protected]>
80
 * @author Jonathan Wage <[email protected]>
81
 * @author Roman Borschel <[email protected]>
82
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
83
 * @author Benjamin Eberlei <[email protected]>
84
 * @todo   Remove any unnecessary methods.
85
 */
86
abstract class AbstractPlatform
87
{
88
    /**
89
     * @var int
90
     */
91
    const CREATE_INDEXES = 1;
92
93
    /**
94
     * @var int
95
     */
96
    const CREATE_FOREIGNKEYS = 2;
97
98
    /**
99
     * @deprecated Use DateIntervalUnit::INTERVAL_UNIT_SECOND.
100
     */
101
    public const DATE_INTERVAL_UNIT_SECOND = DateIntervalUnit::SECOND;
102
103
    /**
104
     * @deprecated Use DateIntervalUnit::MINUTE.
105
     */
106
    public const DATE_INTERVAL_UNIT_MINUTE = DateIntervalUnit::MINUTE;
107
108
    /**
109
     * @deprecated Use DateIntervalUnit::HOUR.
110
     */
111
    public const DATE_INTERVAL_UNIT_HOUR = DateIntervalUnit::HOUR;
112
113
    /**
114
     * @deprecated Use DateIntervalUnit::DAY.
115
     */
116
    public const DATE_INTERVAL_UNIT_DAY = DateIntervalUnit::DAY;
117
118
    /**
119
     * @deprecated Use DateIntervalUnit::WEEK.
120
     */
121
    public const DATE_INTERVAL_UNIT_WEEK = DateIntervalUnit::WEEK;
122
123
    /**
124
     * @deprecated Use DateIntervalUnit::MONTH.
125
     */
126
    public const DATE_INTERVAL_UNIT_MONTH = DateIntervalUnit::MONTH;
127
128
    /**
129
     * @deprecated Use DateIntervalUnit::QUARTER.
130
     */
131
    public const DATE_INTERVAL_UNIT_QUARTER = DateIntervalUnit::QUARTER;
132
133
    /**
134
     * @deprecated Use DateIntervalUnit::QUARTER.
135
     */
136
    public const DATE_INTERVAL_UNIT_YEAR = DateIntervalUnit::YEAR;
137
138
    /**
139
     * @var int
140
     *
141
     * @deprecated Use TrimMode::UNSPECIFIED.
142
     */
143
    public const TRIM_UNSPECIFIED = TrimMode::UNSPECIFIED;
144
145
    /**
146
     * @var int
147
     *
148
     * @deprecated Use TrimMode::LEADING.
149
     */
150
    public const TRIM_LEADING = TrimMode::LEADING;
151
152
    /**
153
     * @var int
154
     *
155
     * @deprecated Use TrimMode::TRAILING.
156
     */
157
    public const TRIM_TRAILING = TrimMode::TRAILING;
158
159
    /**
160
     * @var int
161
     *
162
     * @deprecated Use TrimMode::BOTH.
163
     */
164
    public const TRIM_BOTH = TrimMode::BOTH;
165
166
    /**
167
     * @var array|null
168
     */
169
    protected $doctrineTypeMapping = null;
170
171
    /**
172
     * Contains a list of all columns that should generate parseable column comments for type-detection
173
     * in reverse engineering scenarios.
174
     *
175
     * @var array|null
176
     */
177
    protected $doctrineTypeComments = null;
178
179
    /**
180
     * @var \Doctrine\Common\EventManager
181
     */
182
    protected $_eventManager;
183
184
    /**
185
     * Holds the KeywordList instance for the current platform.
186
     *
187
     * @var \Doctrine\DBAL\Platforms\Keywords\KeywordList
188
     */
189
    protected $_keywords;
190
191
    /**
192
     * Constructor.
193
     */
194 62878
    public function __construct()
195
    {
196 62878
    }
197
198
    /**
199
     * Sets the EventManager used by the Platform.
200
     *
201
     * @param \Doctrine\Common\EventManager $eventManager
202
     */
203 1624
    public function setEventManager(EventManager $eventManager)
204
    {
205 1624
        $this->_eventManager = $eventManager;
206 1624
    }
207
208
    /**
209
     * Gets the EventManager used by the Platform.
210
     *
211
     * @return \Doctrine\Common\EventManager
212
     */
213 1005
    public function getEventManager()
214
    {
215 1005
        return $this->_eventManager;
216
    }
217
218
    /**
219
     * Returns the SQL snippet that declares a boolean column.
220
     *
221
     * @param array $columnDef
222
     *
223
     * @return string
224
     */
225
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
226
227
    /**
228
     * Returns the SQL snippet that declares a 4 byte integer column.
229
     *
230
     * @param array $columnDef
231
     *
232
     * @return string
233
     */
234
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
235
236
    /**
237
     * Returns the SQL snippet that declares an 8 byte integer column.
238
     *
239
     * @param array $columnDef
240
     *
241
     * @return string
242
     */
243
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
244
245
    /**
246
     * Returns the SQL snippet that declares a 2 byte integer column.
247
     *
248
     * @param array $columnDef
249
     *
250
     * @return string
251
     */
252
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
253
254
    /**
255
     * Returns the SQL snippet that declares common properties of an integer column.
256
     *
257
     * @param array $columnDef
258
     *
259
     * @return string
260
     */
261
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
262
263
    /**
264
     * Lazy load Doctrine Type Mappings.
265
     *
266
     * @return void
267
     */
268
    abstract protected function initializeDoctrineTypeMappings();
269
270
    /**
271
     * Initializes Doctrine Type Mappings with the platform defaults
272
     * and with all additional type mappings.
273
     *
274
     * @return void
275
     */
276 1782
    private function initializeAllDoctrineTypeMappings()
277
    {
278 1782
        $this->initializeDoctrineTypeMappings();
279
280 1782
        foreach (Type::getTypesMap() as $typeName => $className) {
281 1782
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
282 1782
                $this->doctrineTypeMapping[$dbType] = $typeName;
283
            }
284
        }
285 1782
    }
286
287
    /**
288
     * Returns the SQL snippet used to declare a VARCHAR column type.
289
     *
290
     * @param array $field
291
     *
292
     * @return string
293
     */
294 6255
    public function getVarcharTypeDeclarationSQL(array $field)
295
    {
296 6255
        if ( !isset($field['length'])) {
297 1489
            $field['length'] = $this->getVarcharDefaultLength();
298
        }
299
300 6255
        $fixed = $field['fixed'] ?? false;
301
302 6255
        if ($field['length'] > $this->getVarcharMaxLength()) {
303
            return $this->getClobTypeDeclarationSQL($field);
304
        }
305
306 6255
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
307
    }
308
309
    /**
310
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
311
     *
312
     * @param array $field The column definition.
313
     *
314
     * @return string
315
     */
316 393
    public function getBinaryTypeDeclarationSQL(array $field)
317
    {
318 393
        if ( ! isset($field['length'])) {
319 342
            $field['length'] = $this->getBinaryDefaultLength();
320
        }
321
322 393
        $fixed = $field['fixed'] ?? false;
323
324 393
        if ($field['length'] > $this->getBinaryMaxLength()) {
325 348
            return $this->getBlobTypeDeclarationSQL($field);
326
        }
327
328 369
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
329
    }
330
331
    /**
332
     * Returns the SQL snippet to declare a GUID/UUID field.
333
     *
334
     * By default this maps directly to a CHAR(36) and only maps to more
335
     * special datatypes when the underlying databases support this datatype.
336
     *
337
     * @param array $field
338
     *
339
     * @return string
340
     */
341 116
    public function getGuidTypeDeclarationSQL(array $field)
342
    {
343 116
        $field['length'] = 36;
344 116
        $field['fixed']  = true;
345
346 116
        return $this->getVarcharTypeDeclarationSQL($field);
347
    }
348
349
    /**
350
     * Returns the SQL snippet to declare a JSON field.
351
     *
352
     * By default this maps directly to a CLOB and only maps to more
353
     * special datatypes when the underlying databases support this datatype.
354
     *
355
     * @param array $field
356
     *
357
     * @return string
358
     */
359 357
    public function getJsonTypeDeclarationSQL(array $field)
360
    {
361 357
        return $this->getClobTypeDeclarationSQL($field);
362
    }
363
364
    /**
365
     * @param int  $length
366
     * @param bool $fixed
367
     *
368
     * @return string
369
     *
370
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
371
     */
372
    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

372
    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...
373
    {
374
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
375
    }
376
377
    /**
378
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
379
     *
380
     * @param int  $length The length of the column.
381
     * @param bool $fixed  Whether the column length is fixed.
382
     *
383
     * @return string
384
     *
385
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
386
     */
387
    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

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

827
            $expression .= /** @scrutinizer ignore-type */ $char . ' ';
Loading history...
828
        }
829
830 540
        if ($mode || $char !== false) {
831 510
            $expression .= 'FROM ';
832
        }
833
834 540
        return 'TRIM(' . $expression . $str . ')';
835
    }
836
837
    /**
838
     * Returns the SQL snippet to trim trailing space characters from the expression.
839
     *
840
     * @param string $str Literal string or column name.
841
     *
842
     * @return string
843
     */
844 72
    public function getRtrimExpression($str)
845
    {
846 72
        return 'RTRIM(' . $str . ')';
847
    }
848
849
    /**
850
     * Returns the SQL snippet to trim leading space characters from the expression.
851
     *
852
     * @param string $str Literal string or column name.
853
     *
854
     * @return string
855
     */
856 72
    public function getLtrimExpression($str)
857
    {
858 72
        return 'LTRIM(' . $str . ')';
859
    }
860
861
    /**
862
     * Returns the SQL snippet to change all characters from the expression to uppercase,
863
     * according to the current character set mapping.
864
     *
865
     * @param string $str Literal string or column name.
866
     *
867
     * @return string
868
     */
869
    public function getUpperExpression($str)
870
    {
871
        return 'UPPER(' . $str . ')';
872
    }
873
874
    /**
875
     * Returns the SQL snippet to change all characters from the expression to lowercase,
876
     * according to the current character set mapping.
877
     *
878
     * @param string $str Literal string or column name.
879
     *
880
     * @return string
881
     */
882
    public function getLowerExpression($str)
883
    {
884
        return 'LOWER(' . $str . ')';
885
    }
886
887
    /**
888
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
889
     *
890
     * @param string   $str      Literal string.
891
     * @param string   $substr   Literal string to find.
892
     * @param int|bool $startPos Position to start at, beginning of string by default.
893
     *
894
     * @return string
895
     *
896
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
897
     */
898
    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

898
    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

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

1069
    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

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

1327
    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

1327
    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

1327
    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...
1328
    {
1329
        throw DBALException::notSupported(__METHOD__);
1330
    }
1331
1332
    /**
1333
     * Returns the SQL bit AND comparison expression.
1334
     *
1335
     * @param string $value1
1336
     * @param string $value2
1337
     *
1338
     * @return string
1339
     */
1340 306
    public function getBitAndComparisonExpression($value1, $value2)
1341
    {
1342 306
        return '(' . $value1 . ' & ' . $value2 . ')';
1343
    }
1344
1345
    /**
1346
     * Returns the SQL bit OR comparison expression.
1347
     *
1348
     * @param string $value1
1349
     * @param string $value2
1350
     *
1351
     * @return string
1352
     */
1353 306
    public function getBitOrComparisonExpression($value1, $value2)
1354
    {
1355 306
        return '(' . $value1 . ' | ' . $value2 . ')';
1356
    }
1357
1358
    /**
1359
     * Returns the FOR UPDATE expression.
1360
     *
1361
     * @return string
1362
     */
1363 30
    public function getForUpdateSQL()
1364
    {
1365 30
        return 'FOR UPDATE';
1366
    }
1367
1368
    /**
1369
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1370
     *
1371
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1372
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1373
     *                             be appended to the FROM clause.
1374
     *
1375
     * @return string
1376
     */
1377 30
    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

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

1734
    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...
1735
    {
1736
        throw DBALException::notSupported(__METHOD__);
1737
    }
1738
1739
    /**
1740
     * Returns the SQL to change a sequence on this platform.
1741
     *
1742
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1743
     *
1744
     * @return string
1745
     *
1746
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1747
     */
1748
    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

1748
    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...
1749
    {
1750
        throw DBALException::notSupported(__METHOD__);
1751
    }
1752
1753
    /**
1754
     * Returns the SQL to create a constraint on a table on this platform.
1755
     *
1756
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1757
     * @param \Doctrine\DBAL\Schema\Table|string $table
1758
     *
1759
     * @return string
1760
     *
1761
     * @throws \InvalidArgumentException
1762
     */
1763 288
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1764
    {
1765 288
        if ($table instanceof Table) {
1766
            $table = $table->getQuotedName($this);
1767
        }
1768
1769 288
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1770
1771 288
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1772
1773 288
        $referencesClause = '';
1774 288
        if ($constraint instanceof Index) {
1775 288
            if ($constraint->isPrimary()) {
1776 288
                $query .= ' PRIMARY KEY';
1777 234
            } elseif ($constraint->isUnique()) {
1778 234
                $query .= ' UNIQUE';
1779
            } else {
1780
                throw new \InvalidArgumentException(
1781 288
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1782
                );
1783
            }
1784 234
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1785 234
            $query .= ' FOREIGN KEY';
1786
1787 234
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1788 234
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1789
        }
1790 288
        $query .= ' '.$columnList.$referencesClause;
1791
1792 288
        return $query;
1793
    }
1794
1795
    /**
1796
     * Returns the SQL to create an index on a table on this platform.
1797
     *
1798
     * @param \Doctrine\DBAL\Schema\Index        $index
1799
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1800
     *
1801
     * @return string
1802
     *
1803
     * @throws \InvalidArgumentException
1804
     */
1805 2879
    public function getCreateIndexSQL(Index $index, $table)
1806
    {
1807 2879
        if ($table instanceof Table) {
1808 18
            $table = $table->getQuotedName($this);
1809
        }
1810 2879
        $name = $index->getQuotedName($this);
1811 2879
        $columns = $index->getQuotedColumns($this);
1812
1813 2879
        if (count($columns) == 0) {
1814
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1815
        }
1816
1817 2879
        if ($index->isPrimary()) {
1818 378
            return $this->getCreatePrimaryKeySQL($index, $table);
1819
        }
1820
1821 2537
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1822 2537
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index);
1823
1824 2537
        return $query;
1825
    }
1826
1827
    /**
1828
     * Adds condition for partial index.
1829
     *
1830
     * @param \Doctrine\DBAL\Schema\Index $index
1831
     *
1832
     * @return string
1833
     */
1834 3489
    protected function getPartialIndexSQL(Index $index)
1835
    {
1836 3489
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1837 97
            return  ' WHERE ' . $index->getOption('where');
1838
        }
1839
1840 3392
        return '';
1841
    }
1842
1843
    /**
1844
     * Adds additional flags for index generation.
1845
     *
1846
     * @param \Doctrine\DBAL\Schema\Index $index
1847
     *
1848
     * @return string
1849
     */
1850 1247
    protected function getCreateIndexSQLFlags(Index $index)
1851
    {
1852 1247
        return $index->isUnique() ? 'UNIQUE ' : '';
1853
    }
1854
1855
    /**
1856
     * Returns the SQL to create an unnamed primary key constraint.
1857
     *
1858
     * @param \Doctrine\DBAL\Schema\Index        $index
1859
     * @param \Doctrine\DBAL\Schema\Table|string $table
1860
     *
1861
     * @return string
1862
     */
1863 306
    public function getCreatePrimaryKeySQL(Index $index, $table)
1864
    {
1865 306
        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

1865
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1866
    }
1867
1868
    /**
1869
     * Returns the SQL to create a named schema.
1870
     *
1871
     * @param string $schemaName
1872
     *
1873
     * @return string
1874
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1875
     */
1876 180
    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

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

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

2926
    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...
2927
    {
2928
        throw DBALException::notSupported(__METHOD__);
2929
    }
2930
2931
    /**
2932
     * @param string $sequenceName
2933
     *
2934
     * @return string
2935
     *
2936
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2937
     */
2938
    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

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

3490
    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...
3491
    {
3492 150
        $tableIdentifier = new Identifier($tableName);
3493
3494 150
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3495
    }
3496
3497
    /**
3498
     * This is for test reasons, many vendors have special requirements for dummy statements.
3499
     *
3500
     * @return string
3501
     */
3502 141
    public function getDummySelectSQL()
3503
    {
3504 141
        $expression = func_num_args() > 0 ? func_get_arg(0) : '1';
3505
3506 141
        return sprintf('SELECT %s', $expression);
3507
    }
3508
3509
    /**
3510
     * Returns the SQL to create a new savepoint.
3511
     *
3512
     * @param string $savepoint
3513
     *
3514
     * @return string
3515
     */
3516 16
    public function createSavePoint($savepoint)
3517
    {
3518 16
        return 'SAVEPOINT ' . $savepoint;
3519
    }
3520
3521
    /**
3522
     * Returns the SQL to release a savepoint.
3523
     *
3524
     * @param string $savepoint
3525
     *
3526
     * @return string
3527
     */
3528 16
    public function releaseSavePoint($savepoint)
3529
    {
3530 16
        return 'RELEASE SAVEPOINT ' . $savepoint;
3531
    }
3532
3533
    /**
3534
     * Returns the SQL to rollback a savepoint.
3535
     *
3536
     * @param string $savepoint
3537
     *
3538
     * @return string
3539
     */
3540 16
    public function rollbackSavePoint($savepoint)
3541
    {
3542 16
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3543
    }
3544
3545
    /**
3546
     * Returns the keyword list instance of this platform.
3547
     *
3548
     * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList
3549
     *
3550
     * @throws \Doctrine\DBAL\DBALException If no keyword list is specified.
3551
     */
3552 20232
    final public function getReservedKeywordsList()
3553
    {
3554
        // Check for an existing instantiation of the keywords class.
3555 20232
        if ($this->_keywords) {
3556 19026
            return $this->_keywords;
3557
        }
3558
3559 17497
        $class = $this->getReservedKeywordsClass();
3560 17497
        $keywords = new $class;
3561 17497
        if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) {
3562
            throw DBALException::notSupported(__METHOD__);
3563
        }
3564
3565
        // Store the instance so it doesn't need to be generated on every request.
3566 17497
        $this->_keywords = $keywords;
3567
3568 17497
        return $keywords;
3569
    }
3570
3571
    /**
3572
     * Returns the class name of the reserved keywords list.
3573
     *
3574
     * @return string
3575
     *
3576
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3577
     */
3578
    protected function getReservedKeywordsClass()
3579
    {
3580
        throw DBALException::notSupported(__METHOD__);
3581
    }
3582
3583
    /**
3584
     * Quotes a literal string.
3585
     * This method is NOT meant to fix SQL injections!
3586
     * It is only meant to escape this platform's string literal
3587
     * quote character inside the given literal string.
3588
     *
3589
     * @param string $str The literal string to be quoted.
3590
     *
3591
     * @return string The quoted literal string.
3592
     */
3593 6723
    public function quoteStringLiteral($str)
3594
    {
3595 6723
        $c = $this->getStringLiteralQuoteCharacter();
3596
3597 6723
        return $c . str_replace($c, $c . $c, $str) . $c;
3598
    }
3599
3600
    /**
3601
     * Gets the character used for string literal quoting.
3602
     *
3603
     * @return string
3604
     */
3605 7047
    public function getStringLiteralQuoteCharacter()
3606
    {
3607 7047
        return "'";
3608
    }
3609
3610
    /**
3611
     * Escapes metacharacters in a string intended to be used with a LIKE
3612
     * operator.
3613
     *
3614
     * @param string $inputString a literal, unquoted string
3615
     * @param string $escapeChar  should be reused by the caller in the LIKE
3616
     *                            expression.
3617
     */
3618 342
    final public function escapeStringForLike(string $inputString, string $escapeChar) : string
3619
    {
3620 342
        return preg_replace(
3621 342
            '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u',
3622 342
            addcslashes($escapeChar, '\\') . '$1',
3623 342
            $inputString
3624
        );
3625
    }
3626
3627 342
    protected function getLikeWildcardCharacters() : string
3628
    {
3629 342
        return '%_';
3630
    }
3631
}
3632