Passed
Pull Request — master (#3133)
by Sergei
04:15
created

AbstractPlatform::getIdentitySequenceName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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

372
    protected function getVarcharTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

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

Loading history...
373
    {
374
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
375
    }
376
377
    /**
378
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
379
     *
380
     * @param int  $length The length of the column.
381
     * @param bool $fixed  Whether the column length is fixed.
382
     *
383
     * @return string
384
     *
385
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
386
     */
387
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
0 ignored issues
show
Unused Code introduced by
The parameter $fixed is not used and could be removed. ( Ignorable by Annotation )

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

387
    protected function getBinaryTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

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

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

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

906
    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

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

1077
    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

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

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

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

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

1335
    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

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

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

1742
    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...
1743
    {
1744
        throw DBALException::notSupported(__METHOD__);
1745
    }
1746
1747
    /**
1748
     * Returns the SQL to change a sequence on this platform.
1749
     *
1750
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1751
     *
1752
     * @return string
1753
     *
1754
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1755
     */
1756
    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

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

1873
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1874 170
    }
1875
1876 170
    /**
1877
     * Returns the SQL to create a named schema.
1878
     *
1879
     * @param string $schemaName
1880
     *
1881
     * @return string
1882
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1883
     */
1884
    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

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

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

2934
    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...
2935
    {
2936
        throw DBALException::notSupported(__METHOD__);
2937
    }
2938
2939
    /**
2940
     * @param string $sequenceName
2941
     *
2942
     * @return string
2943
     *
2944
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2945
     */
2946
    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

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

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