Passed
Pull Request — master (#3092)
by Michael
13:56
created

AbstractPlatform::onSchemaAlterTableRenameColumn()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

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

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

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

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

896
    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

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

1067
    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

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

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

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

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

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

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

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

Loading history...
Unused Code introduced by
The parameter $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

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

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

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

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

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

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

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

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

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

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