Passed
Push — tests-better-coverage ( b00e66...9c1c22 )
by Michael
23:49
created

AbstractPlatform::getDefaultValueDeclarationSQL()   C

Complexity

Conditions 12
Paths 9

Size

Total Lines 35
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 12.0247

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 17
cts 18
cp 0.9444
rs 5.1612
c 0
b 0
f 0
cc 12
eloc 17
nc 9
nop 1
crap 12.0247

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

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

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

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

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

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

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

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

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

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

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

896
    public function getLocateExpression($str, /** @scrutinizer ignore-unused */ $substr, $startPos = false)

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

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

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

896
    public function getLocateExpression($str, $substr, /** @scrutinizer ignore-unused */ $startPos = false)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1375
    public function appendLockHint($fromClause, /** @scrutinizer ignore-unused */ $lockMode)

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

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

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

1732
    public function getCreateSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

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

Loading history...
1733
    {
1734
        throw DBALException::notSupported(__METHOD__);
1735
    }
1736
1737
    /**
1738
     * Returns the SQL to change a sequence on this platform.
1739
     *
1740
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1741
     *
1742
     * @return string
1743
     *
1744
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1745
     */
1746
    public function getAlterSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

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

1746
    public function getAlterSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

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

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

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

1863
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1864
    }
1865
1866
    /**
1867
     * Returns the SQL to create a named schema.
1868
     *
1869
     * @param string $schemaName
1870
     *
1871
     * @return string
1872
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1873
     */
1874 170
    public function getCreateSchemaSQL($schemaName)
0 ignored issues
show
Unused Code introduced by
The parameter $schemaName is not used and could be removed. ( Ignorable by Annotation )

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

1874
    public function getCreateSchemaSQL(/** @scrutinizer ignore-unused */ $schemaName)

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

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

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

2609
    public function getColumnCharsetDeclarationSQL(/** @scrutinizer ignore-unused */ $charset)

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

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

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

2924
    public function getDropSequenceSQL(/** @scrutinizer ignore-unused */ $sequence)

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

Loading history...
2925
    {
2926
        throw DBALException::notSupported(__METHOD__);
2927
    }
2928
2929
    /**
2930
     * @param string $sequenceName
2931
     *
2932
     * @return string
2933
     *
2934
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2935
     */
2936
    public function getSequenceNextValSQL($sequenceName)
0 ignored issues
show
Unused Code introduced by
The parameter $sequenceName is not used and could be removed. ( Ignorable by Annotation )

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

2936
    public function getSequenceNextValSQL(/** @scrutinizer ignore-unused */ $sequenceName)

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

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

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

3488
    public function getTruncateTableSQL($tableName, /** @scrutinizer ignore-unused */ $cascade = false)

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

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