Passed
Pull Request — develop (#3248)
by Sergei
23:58
created

AbstractPlatform::getRenameIndexSQL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

357
    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...
358
    {
359
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
360
    }
361
362
    /**
363
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
364
     *
365
     * @param int  $length The length of the column.
366
     * @param bool $fixed  Whether the column length is fixed.
367
     *
368
     * @return string
369
     *
370
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
371
     */
372
    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

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

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

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

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

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

Loading history...
795 117
                $expression = 'LEADING ';
796 117
                break;
797
798
            case TrimMode::TRAILING:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

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

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

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

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

Loading history...
799 117
                $expression = 'TRAILING ';
800 117
                break;
801
802
            case TrimMode::BOTH:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

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

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

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

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

Loading history...
803 117
                $expression = 'BOTH ';
804 117
                break;
805
        }
806
807 468
        if ($char !== false) {
808 364
            $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

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

879
    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

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

1050
    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

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

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

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

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

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

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

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

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

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

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

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

1722
    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...
1723
    {
1724
        throw DBALException::notSupported(__METHOD__);
1725
    }
1726
1727
    /**
1728
     * Returns the SQL to change a sequence on this platform.
1729
     *
1730
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1731
     *
1732
     * @return string
1733
     *
1734
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1735
     */
1736
    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

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

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

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

2871
    public function getListTableIndexesSQL($table, /** @scrutinizer ignore-unused */ $currentDatabase = null)

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...
2872
    {
2873
        throw DBALException::notSupported(__METHOD__);
2874
    }
2875
2876
    /**
2877
     * @param string $table
2878
     *
2879
     * @return string
2880
     *
2881
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2882
     */
2883
    public function getListTableForeignKeysSQL($table)
2884
    {
2885
        throw DBALException::notSupported(__METHOD__);
2886
    }
2887
2888
    /**
2889
     * @param string $name
2890
     * @param string $sql
2891
     *
2892
     * @return string
2893
     *
2894
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2895
     */
2896
    public function getCreateViewSQL($name, $sql)
2897
    {
2898
        throw DBALException::notSupported(__METHOD__);
2899
    }
2900
2901
    /**
2902
     * @param string $name
2903
     *
2904
     * @return string
2905
     *
2906
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2907
     */
2908
    public function getDropViewSQL($name)
2909
    {
2910
        throw DBALException::notSupported(__METHOD__);
2911
    }
2912
2913
    /**
2914
     * Returns the SQL snippet to drop an existing sequence.
2915
     *
2916
     * @param Sequence|string $sequence
2917
     *
2918
     * @return string
2919
     *
2920
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2921
     */
2922
    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

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

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

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