Completed
Pull Request — master (#3212)
by Sergei
49:12 queued 45:02
created

AbstractPlatform::getNowExpression()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

388
    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...
389
    {
390
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
391
    }
392
393
    /**
394
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
395
     *
396
     * @param int  $length The length of the column.
397
     * @param bool $fixed  Whether the column length is fixed.
398
     *
399
     * @return string
400
     *
401
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
402
     */
403
    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

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

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

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

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

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

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

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

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

1097
    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

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

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

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

Loading history...
Unused Code introduced by
The parameter $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

1355
    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

1355
    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...
1356
    {
1357
        throw DBALException::notSupported(__METHOD__);
1358
    }
1359
1360
    /**
1361
     * Returns the SQL bit AND comparison expression.
1362
     *
1363
     * @param string $value1
1364
     * @param string $value2
1365
     *
1366
     * @return string
1367
     */
1368 304
    public function getBitAndComparisonExpression($value1, $value2)
1369
    {
1370 304
        return '(' . $value1 . ' & ' . $value2 . ')';
1371
    }
1372
1373
    /**
1374
     * Returns the SQL bit OR comparison expression.
1375
     *
1376
     * @param string $value1
1377
     * @param string $value2
1378
     *
1379
     * @return string
1380
     */
1381 304
    public function getBitOrComparisonExpression($value1, $value2)
1382
    {
1383 304
        return '(' . $value1 . ' | ' . $value2 . ')';
1384
    }
1385
1386
    /**
1387
     * Returns the FOR UPDATE expression.
1388
     *
1389
     * @return string
1390
     */
1391 30
    public function getForUpdateSQL()
1392
    {
1393 30
        return 'FOR UPDATE';
1394
    }
1395
1396
    /**
1397
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1398
     *
1399
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1400
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1401
     *                             be appended to the FROM clause.
1402
     *
1403
     * @return string
1404
     */
1405 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

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

1762
    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...
1763
    {
1764
        throw DBALException::notSupported(__METHOD__);
1765
    }
1766
1767
    /**
1768
     * Returns the SQL to change a sequence on this platform.
1769
     *
1770
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1771
     *
1772
     * @return string
1773
     *
1774
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1775
     */
1776
    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

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

1893
        return 'ALTER TABLE ' . /** @scrutinizer ignore-type */ $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
Loading history...
1894
    }
1895
1896
    /**
1897
     * Returns the SQL to create a named schema.
1898
     *
1899
     * @param string $schemaName
1900
     *
1901
     * @return string
1902
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1903
     */
1904 180
    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

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

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

2954
    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...
2955
    {
2956
        throw DBALException::notSupported(__METHOD__);
2957
    }
2958
2959
    /**
2960
     * @param string $sequenceName
2961
     *
2962
     * @return string
2963
     *
2964
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2965
     */
2966
    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

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

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