Passed
Pull Request — master (#3133)
by Sergei
03:28
created

AbstractPlatform::getTemporaryTableName()   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
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Platforms;
21
22
use Doctrine\Common\EventManager;
23
use Doctrine\DBAL\DBALException;
24
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
25
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
26
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
27
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
28
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
29
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
30
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
31
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
32
use Doctrine\DBAL\Events;
33
use Doctrine\DBAL\Schema\Column;
34
use Doctrine\DBAL\Schema\ColumnDiff;
35
use Doctrine\DBAL\Schema\Constraint;
36
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
37
use Doctrine\DBAL\Schema\Identifier;
38
use Doctrine\DBAL\Schema\Index;
39
use Doctrine\DBAL\Schema\Sequence;
40
use Doctrine\DBAL\Schema\Table;
41
use Doctrine\DBAL\Schema\TableDiff;
42
use Doctrine\DBAL\TransactionIsolationLevel;
43
use Doctrine\DBAL\Types;
44
use Doctrine\DBAL\Types\Type;
45
use 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
        $maxLength = $fixed
303
            ? $this->getCharMaxLength()
304 5905
            : $this->getVarcharMaxLength();
305
306
        if ($field['length'] > $maxLength) {
307
            return $this->getClobTypeDeclarationSQL($field);
308
        }
309
310
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
311
    }
312
313
    /**
314 371
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
315
     *
316 371
     * @param array $field The column definition.
317 323
     *
318
     * @return string
319
     */
320 371
    public function getBinaryTypeDeclarationSQL(array $field)
321
    {
322 371
        if ( ! isset($field['length'])) {
323 327
            $field['length'] = $this->getBinaryDefaultLength();
324
        }
325
326 350
        $fixed = $field['fixed'] ?? false;
327
328
        if ($field['length'] > $this->getBinaryMaxLength()) {
329
            return $this->getBlobTypeDeclarationSQL($field);
330
        }
331
332
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
333
    }
334
335
    /**
336
     * Returns the SQL snippet to declare a GUID/UUID field.
337
     *
338
     * By default this maps directly to a CHAR(36) and only maps to more
339 110
     * special datatypes when the underlying databases support this datatype.
340
     *
341 110
     * @param array $field
342 110
     *
343
     * @return string
344 110
     */
345
    public function getGuidTypeDeclarationSQL(array $field)
346
    {
347
        $field['length'] = 36;
348
        $field['fixed']  = true;
349
350
        return $this->getVarcharTypeDeclarationSQL($field);
351
    }
352
353
    /**
354
     * Returns the SQL snippet to declare a JSON field.
355
     *
356
     * By default this maps directly to a CLOB and only maps to more
357 344
     * special datatypes when the underlying databases support this datatype.
358
     *
359 344
     * @param array $field
360
     *
361
     * @return string
362
     */
363
    public function getJsonTypeDeclarationSQL(array $field)
364
    {
365
        return $this->getClobTypeDeclarationSQL($field);
366
    }
367
368
    /**
369
     * @param int  $length
370
     * @param bool $fixed
371
     *
372
     * @return string
373
     *
374
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
375
     */
376
    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

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

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

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

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

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

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

1081
    public function getDateDiffExpression(/** @scrutinizer ignore-unused */ $date1, $date2)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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