Passed
Pull Request — master (#3133)
by Michael
17:35
created

AbstractPlatform::supportsInlineColumnComments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
826 144
                $expression = 'LEADING ';
827 144
                break;
828
829 432
            case TrimMode::TRAILING:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

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

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

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

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

Loading history...
830 144
                $expression = 'TRAILING ';
831 144
                break;
832
833 288
            case TrimMode::BOTH:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

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

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

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

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

Loading history...
834 144
                $expression = 'BOTH ';
835 144
                break;
836
        }
837
838 576
        if ($char !== false) {
839 448
            $expression .= $char . ' ';
0 ignored issues
show
Bug introduced by
Are you sure $char of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1747
    {
1748
        throw DBALException::notSupported(__METHOD__);
1749
    }
1750
1751
    /**
1752
     * Returns the SQL to change a sequence on this platform.
1753
     *
1754
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1755
     *
1756
     * @return string
1757
     *
1758
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1759
     */
1760
    public function getAlterSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

1877
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1878
    }
1879
1880
    /**
1881
     * Returns the SQL to create a named schema.
1882
     *
1883
     * @param string $schemaName
1884
     *
1885
     * @return string
1886
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1887
     */
1888 190
    public function getCreateSchemaSQL($schemaName)
0 ignored issues
show
Unused Code introduced by
The parameter $schemaName is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

Loading history...
2939
    {
2940
        throw DBALException::notSupported(__METHOD__);
2941
    }
2942
2943
    /**
2944
     * @param string $sequenceName
2945
     *
2946
     * @return string
2947
     *
2948
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2949
     */
2950
    public function getSequenceNextValSQL($sequenceName)
0 ignored issues
show
Unused Code introduced by
The parameter $sequenceName is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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