Failed Conditions
Pull Request — master (#3013)
by Grégoire
13:49
created

AbstractPlatform::escapeStringForLike()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

346
    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...
347
    {
348
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
349
    }
350
351
    /**
352
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
353
     *
354
     * @param int  $length The length of the column.
355
     * @param bool $fixed  Whether the column length is fixed.
356
     *
357
     * @return string
358
     *
359
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
360
     */
361
    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

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

801
            $expression .= /** @scrutinizer ignore-type */ $char . ' ';
Loading history...
802
        }
803
804
        if ($mode || $char !== false) {
805
            $expression .= 'FROM ';
806
        }
807
808
        return 'TRIM(' . $expression . $str . ')';
809
    }
810
811
    /**
812
     * Returns the SQL snippet to trim trailing space characters from the expression.
813
     *
814
     * @param string $str Literal string or column name.
815
     *
816
     * @return string
817
     */
818 4
    public function getRtrimExpression($str)
819
    {
820 4
        return 'RTRIM(' . $str . ')';
821
    }
822
823
    /**
824
     * Returns the SQL snippet to trim leading space characters from the expression.
825
     *
826
     * @param string $str Literal string or column name.
827
     *
828
     * @return string
829
     */
830 4
    public function getLtrimExpression($str)
831
    {
832 4
        return 'LTRIM(' . $str . ')';
833
    }
834
835
    /**
836
     * Returns the SQL snippet to change all characters from the expression to uppercase,
837
     * according to the current character set mapping.
838
     *
839
     * @param string $str Literal string or column name.
840
     *
841
     * @return string
842
     */
843
    public function getUpperExpression($str)
844
    {
845
        return 'UPPER(' . $str . ')';
846
    }
847
848
    /**
849
     * Returns the SQL snippet to change all characters from the expression to lowercase,
850
     * according to the current character set mapping.
851
     *
852
     * @param string $str Literal string or column name.
853
     *
854
     * @return string
855
     */
856
    public function getLowerExpression($str)
857
    {
858
        return 'LOWER(' . $str . ')';
859
    }
860
861
    /**
862
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
863
     *
864
     * @param string   $str      Literal string.
865
     * @param string   $substr   Literal string to find.
866
     * @param int|bool $startPos Position to start at, beginning of string by default.
867
     *
868
     * @return string
869
     *
870
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
871
     */
872
    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

872
    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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1301
    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...
1302
    {
1303
        throw DBALException::notSupported(__METHOD__);
1304
    }
1305
1306
    /**
1307
     * Returns the SQL bit AND comparison expression.
1308
     *
1309
     * @param string $value1
1310
     * @param string $value2
1311
     *
1312
     * @return string
1313
     */
1314 17
    public function getBitAndComparisonExpression($value1, $value2)
1315
    {
1316 17
        return '(' . $value1 . ' & ' . $value2 . ')';
1317
    }
1318
1319
    /**
1320
     * Returns the SQL bit OR comparison expression.
1321
     *
1322
     * @param string $value1
1323
     * @param string $value2
1324
     *
1325
     * @return string
1326
     */
1327 17
    public function getBitOrComparisonExpression($value1, $value2)
1328
    {
1329 17
        return '(' . $value1 . ' | ' . $value2 . ')';
1330
    }
1331
1332
    /**
1333
     * Returns the FOR UPDATE expression.
1334
     *
1335
     * @return string
1336
     */
1337
    public function getForUpdateSQL()
1338
    {
1339
        return 'FOR UPDATE';
1340
    }
1341
1342
    /**
1343
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1344
     *
1345
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1346
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1347
     *                             be appended to the FROM clause.
1348
     *
1349
     * @return string
1350
     */
1351
    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

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

1708
    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...
1709
    {
1710
        throw DBALException::notSupported(__METHOD__);
1711
    }
1712
1713
    /**
1714
     * Returns the SQL to change a sequence on this platform.
1715
     *
1716
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1717
     *
1718
     * @return string
1719
     *
1720
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1721
     */
1722
    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

1722
    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...
1723
    {
1724
        throw DBALException::notSupported(__METHOD__);
1725
    }
1726
1727
    /**
1728
     * Returns the SQL to create a constraint on a table on this platform.
1729
     *
1730
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1731
     * @param \Doctrine\DBAL\Schema\Table|string $table
1732
     *
1733
     * @return string
1734
     *
1735
     * @throws \InvalidArgumentException
1736
     */
1737 16
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1738
    {
1739 16
        if ($table instanceof Table) {
1740
            $table = $table->getQuotedName($this);
1741
        }
1742
1743 16
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1744
1745 16
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1746
1747 16
        $referencesClause = '';
1748 16
        if ($constraint instanceof Index) {
1749 16
            if ($constraint->isPrimary()) {
1750 16
                $query .= ' PRIMARY KEY';
1751 13
            } elseif ($constraint->isUnique()) {
1752 13
                $query .= ' UNIQUE';
1753
            } else {
1754
                throw new \InvalidArgumentException(
1755 16
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1756
                );
1757
            }
1758 13
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1759 13
            $query .= ' FOREIGN KEY';
1760
1761 13
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1762 13
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1763
        }
1764 16
        $query .= ' '.$columnList.$referencesClause;
1765
1766 16
        return $query;
1767
    }
1768
1769
    /**
1770
     * Returns the SQL to create an index on a table on this platform.
1771
     *
1772
     * @param \Doctrine\DBAL\Schema\Index        $index
1773
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1774
     *
1775
     * @return string
1776
     *
1777
     * @throws \InvalidArgumentException
1778
     */
1779 155
    public function getCreateIndexSQL(Index $index, $table)
1780
    {
1781 155
        if ($table instanceof Table) {
1782 1
            $table = $table->getQuotedName($this);
1783
        }
1784 155
        $name = $index->getQuotedName($this);
1785 155
        $columns = $index->getQuotedColumns($this);
1786
1787 155
        if (count($columns) == 0) {
1788
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1789
        }
1790
1791 155
        if ($index->isPrimary()) {
1792 21
            return $this->getCreatePrimaryKeySQL($index, $table);
1793
        }
1794
1795 136
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1796 136
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index);
1797
1798 136
        return $query;
1799
    }
1800
1801
    /**
1802
     * Adds condition for partial index.
1803
     *
1804
     * @param \Doctrine\DBAL\Schema\Index $index
1805
     *
1806
     * @return string
1807
     */
1808 183
    protected function getPartialIndexSQL(Index $index)
1809
    {
1810 183
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1811 5
            return  ' WHERE ' . $index->getOption('where');
1812
        }
1813
1814 178
        return '';
1815
    }
1816
1817
    /**
1818
     * Adds additional flags for index generation.
1819
     *
1820
     * @param \Doctrine\DBAL\Schema\Index $index
1821
     *
1822
     * @return string
1823
     */
1824 67
    protected function getCreateIndexSQLFlags(Index $index)
1825
    {
1826 67
        return $index->isUnique() ? 'UNIQUE ' : '';
1827
    }
1828
1829
    /**
1830
     * Returns the SQL to create an unnamed primary key constraint.
1831
     *
1832
     * @param \Doctrine\DBAL\Schema\Index        $index
1833
     * @param \Doctrine\DBAL\Schema\Table|string $table
1834
     *
1835
     * @return string
1836
     */
1837 17
    public function getCreatePrimaryKeySQL(Index $index, $table)
1838
    {
1839 17
        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

1839
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1840
    }
1841
1842
    /**
1843
     * Returns the SQL to create a named schema.
1844
     *
1845
     * @param string $schemaName
1846
     *
1847
     * @return string
1848
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1849
     */
1850 10
    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

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

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
2518 82
            case 'SET NULL':
2519 61
            case 'NO ACTION':
2520 48
            case 'RESTRICT':
2521 34
            case 'SET DEFAULT':
2522 104
                return $upper;
2523
            default:
2524 17
                throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper);
2525
        }
2526
    }
2527
2528
    /**
2529
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2530
     * of a field declaration to be used in statements like CREATE TABLE.
2531
     *
2532
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2533
     *
2534
     * @return string
2535
     *
2536
     * @throws \InvalidArgumentException
2537
     */
2538 73
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2539
    {
2540 73
        $sql = '';
2541 73
        if (strlen($foreignKey->getName())) {
2542 59
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2543
        }
2544 73
        $sql .= 'FOREIGN KEY (';
2545
2546 73
        if (count($foreignKey->getLocalColumns()) === 0) {
2547
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
2548
        }
2549 73
        if (count($foreignKey->getForeignColumns()) === 0) {
2550
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
2551
        }
2552 73
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2553
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2554
        }
2555
2556 73
        $sql .= implode(', ', $foreignKey->getQuotedLocalColumns($this))
2557 73
            . ') REFERENCES '
2558 73
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2559 73
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2560
2561 73
        return $sql;
2562
    }
2563
2564
    /**
2565
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2566
     * of a field declaration to be used in statements like CREATE TABLE.
2567
     *
2568
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2569
     *                of a field declaration.
2570
     */
2571
    public function getUniqueFieldDeclarationSQL()
2572
    {
2573
        return 'UNIQUE';
2574
    }
2575
2576
    /**
2577
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2578
     * of a field declaration to be used in statements like CREATE TABLE.
2579
     *
2580
     * @param string $charset The name of the charset.
2581
     *
2582
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2583
     *                of a field declaration.
2584
     */
2585
    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

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

2900
    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...
2901
    {
2902
        throw DBALException::notSupported(__METHOD__);
2903
    }
2904
2905
    /**
2906
     * @param string $sequenceName
2907
     *
2908
     * @return string
2909
     *
2910
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2911
     */
2912
    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

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

3464
    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...
3465
    {
3466 3
        $tableIdentifier = new Identifier($tableName);
3467
3468 3
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3469
    }
3470
3471
    /**
3472
     * This is for test reasons, many vendors have special requirements for dummy statements.
3473
     *
3474
     * @return string
3475
     */
3476 7
    public function getDummySelectSQL()
3477
    {
3478 7
        return 'SELECT 1';
3479
    }
3480
3481
    /**
3482
     * Returns the SQL to create a new savepoint.
3483
     *
3484
     * @param string $savepoint
3485
     *
3486
     * @return string
3487
     */
3488 1
    public function createSavePoint($savepoint)
3489
    {
3490 1
        return 'SAVEPOINT ' . $savepoint;
3491
    }
3492
3493
    /**
3494
     * Returns the SQL to release a savepoint.
3495
     *
3496
     * @param string $savepoint
3497
     *
3498
     * @return string
3499
     */
3500 1
    public function releaseSavePoint($savepoint)
3501
    {
3502 1
        return 'RELEASE SAVEPOINT ' . $savepoint;
3503
    }
3504
3505
    /**
3506
     * Returns the SQL to rollback a savepoint.
3507
     *
3508
     * @param string $savepoint
3509
     *
3510
     * @return string
3511
     */
3512 1
    public function rollbackSavePoint($savepoint)
3513
    {
3514 1
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3515
    }
3516
3517
    /**
3518
     * Returns the keyword list instance of this platform.
3519
     *
3520
     * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList
3521
     *
3522
     * @throws \Doctrine\DBAL\DBALException If no keyword list is specified.
3523
     */
3524 1077
    final public function getReservedKeywordsList()
3525
    {
3526
        // Check for an existing instantiation of the keywords class.
3527 1077
        if ($this->_keywords) {
3528 1010
            return $this->_keywords;
3529
        }
3530
3531 953
        $class = $this->getReservedKeywordsClass();
3532 953
        $keywords = new $class;
3533 953
        if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) {
3534
            throw DBALException::notSupported(__METHOD__);
3535
        }
3536
3537
        // Store the instance so it doesn't need to be generated on every request.
3538 953
        $this->_keywords = $keywords;
3539
3540 953
        return $keywords;
3541
    }
3542
3543
    /**
3544
     * Returns the class name of the reserved keywords list.
3545
     *
3546
     * @return string
3547
     *
3548
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3549
     */
3550
    protected function getReservedKeywordsClass()
3551
    {
3552
        throw DBALException::notSupported(__METHOD__);
3553
    }
3554
3555
    /**
3556
     * Quotes a literal string.
3557
     * This method is NOT meant to fix SQL injections!
3558
     * It is only meant to escape this platform's string literal
3559
     * quote character inside the given literal string.
3560
     *
3561
     * @param string $str The literal string to be quoted.
3562
     *
3563
     * @return string The quoted literal string.
3564
     */
3565 334
    public function quoteStringLiteral($str)
3566
    {
3567 334
        $c = $this->getStringLiteralQuoteCharacter();
3568
3569 334
        return $c . str_replace($c, $c . $c, $str) . $c;
3570
    }
3571
3572
    /**
3573
     * Gets the character used for string literal quoting.
3574
     *
3575
     * @return string
3576
     */
3577 352
    public function getStringLiteralQuoteCharacter()
3578
    {
3579 352
        return "'";
3580
    }
3581
3582
    /**
3583
     * Escapes metacharacters in a string intended to be used with a LIKE
3584
     * operator.
3585
     */
3586
    public function escapeStringForLike(string $untrustedString): string
3587
    {
3588
        $escapeChar = $this->getLikeEscapeChar();
3589
        $replacePairs = [$escapeChar => $escapeChar.$escapeChar];
3590
        foreach ($this->getLikeWildcardCharacters() as $metaChar) {
3591
            $replacePairs[$metaCharacter] = $escapeChar.$metaChar;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $metaCharacter seems to be never defined.
Loading history...
3592
        }
3593
3594
        return strtr($untrustedString, $replacePairs);
3595
    }
3596
3597
    protected function getLikeEscapeChar(): string
3598
    {
3599
        return '\\';
3600
    }
3601
3602
    protected function getLikeWildcardCharacters(): iterable
3603
    {
3604
        return ['%', '_'];
3605
    }
3606
}
3607