AbstractPlatform::getDateSubHourExpression()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
    public function __construct()
197
    {
198
    }
199
200
    /**
201
     * Sets the EventManager used by the Platform.
202
     *
203
     * @param \Doctrine\Common\EventManager $eventManager
204
     */
205
    public function setEventManager(EventManager $eventManager)
206
    {
207
        $this->_eventManager = $eventManager;
208
    }
209
210
    /**
211
     * Gets the EventManager used by the Platform.
212
     *
213
     * @return \Doctrine\Common\EventManager
214
     */
215
    public function getEventManager()
216
    {
217
        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
    private function initializeAllDoctrineTypeMappings()
279
    {
280
        $this->initializeDoctrineTypeMappings();
281
282
        foreach (Type::getTypesMap() as $typeName => $className) {
283
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
284
                $this->doctrineTypeMapping[$dbType] = $typeName;
285
            }
286
        }
287
    }
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
    public function getVarcharTypeDeclarationSQL(array $field)
297
    {
298
        if ( !isset($field['length'])) {
299
            $field['length'] = $this->getVarcharDefaultLength();
300
        }
301
302
        $fixed = $field['fixed'] ?? false;
303
304
        $maxLength = $fixed
305
            ? $this->getCharMaxLength()
306
            : $this->getVarcharMaxLength();
307
308
        if ($field['length'] > $maxLength) {
309
            return $this->getClobTypeDeclarationSQL($field);
310
        }
311
312
        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
    public function getBinaryTypeDeclarationSQL(array $field)
323
    {
324
        if ( ! isset($field['length'])) {
325
            $field['length'] = $this->getBinaryDefaultLength();
326
        }
327
328
        $fixed = $field['fixed'] ?? false;
329
330
        $maxLength = $this->getBinaryMaxLength();
331
332
        if ($field['length'] > $maxLength) {
333
            if ($maxLength > 0) {
334
                @trigger_error(sprintf(
335
                    'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.',
336
                    $field['length'],
337
                    $maxLength
338
                ), E_USER_DEPRECATED);
339
            }
340
341
            return $this->getBlobTypeDeclarationSQL($field);
342
        }
343
344
        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
    public function getGuidTypeDeclarationSQL(array $field)
358
    {
359
        $field['length'] = 36;
360
        $field['fixed']  = true;
361
362
        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
    public function getJsonTypeDeclarationSQL(array $field)
376
    {
377
        return $this->getClobTypeDeclarationSQL($field);
378
    }
379
380
    /**
381
     * @param int  $length
382
     * @param bool $fixed
383
     *
384
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
385
     *
386
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
387
     */
388
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
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
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
400
     *
401
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
402
     */
403
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
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
    public function registerDoctrineTypeMapping($dbType, $doctrineType)
442
    {
443
        if ($this->doctrineTypeMapping === null) {
444
            $this->initializeAllDoctrineTypeMappings();
445
        }
446
447
        if (!Types\Type::hasType($doctrineType)) {
448
            throw DBALException::typeNotFound($doctrineType);
449
        }
450
451
        $dbType = strtolower($dbType);
452
        $this->doctrineTypeMapping[$dbType] = $doctrineType;
453
454
        $doctrineType = Type::getType($doctrineType);
455
456
        if ($doctrineType->requiresSQLCommentHint($this)) {
457
            $this->markDoctrineTypeCommented($doctrineType);
458
        }
459
    }
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
    public function getDoctrineTypeMapping($dbType)
471
    {
472
        if ($this->doctrineTypeMapping === null) {
473
            $this->initializeAllDoctrineTypeMappings();
474
        }
475
476
        $dbType = strtolower($dbType);
477
478
        if (!isset($this->doctrineTypeMapping[$dbType])) {
479
            throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it.");
480
        }
481
482
        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
    public function hasDoctrineTypeMappingFor($dbType)
493
    {
494
        if ($this->doctrineTypeMapping === null) {
495
            $this->initializeAllDoctrineTypeMappings();
496
        }
497
498
        $dbType = strtolower($dbType);
499
500
        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
    protected function initializeCommentedDoctrineTypes()
509
    {
510
        $this->doctrineTypeComments = [];
511
512
        foreach (Type::getTypesMap() as $typeName => $className) {
513
            $type = Type::getType($typeName);
514
515
            if ($type->requiresSQLCommentHint($this)) {
516
                $this->doctrineTypeComments[] = $typeName;
517
            }
518
        }
519
    }
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
    public function isCommentedDoctrineType(Type $doctrineType)
529
    {
530
        if ($this->doctrineTypeComments === null) {
531
            $this->initializeCommentedDoctrineTypes();
532
        }
533
534
        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
    public function markDoctrineTypeCommented($doctrineType)
545
    {
546
        if ($this->doctrineTypeComments === null) {
547
            $this->initializeCommentedDoctrineTypes();
548
        }
549
550
        $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
551
    }
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
    public function getDoctrineTypeComment(Type $doctrineType)
561
    {
562
        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
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
571
     */
572
    protected function getColumnComment(Column $column)
573
    {
574
        $comment = $column->getComment();
575
576
        if ($this->isCommentedDoctrineType($column->getType())) {
577
            $comment .= $this->getDoctrineTypeComment($column->getType());
578
        }
579
580
        return $comment;
581
    }
582
583
    /**
584
     * Gets the character used for identifier quoting.
585
     *
586
     * @return string
587
     */
588
    public function getIdentifierQuoteCharacter()
589
    {
590
        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
    public function getCharMaxLength() : int
617
    {
618
        return $this->getVarcharMaxLength();
619
    }
620
621
    /**
622
     * Gets the maximum length of a varchar field.
623
     *
624
     * @return int
625
     */
626
    public function getVarcharMaxLength()
627
    {
628
        return 4000;
629
    }
630
631
    /**
632
     * Gets the default length of a varchar field.
633
     *
634
     * @return int
635
     */
636
    public function getVarcharDefaultLength()
637
    {
638
        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
    public function getBinaryDefaultLength()
657
    {
658
        return 255;
659
    }
660
661
    /**
662
     * Gets all SQL wildcard characters of the platform.
663
     *
664
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
665
     */
666
    public function getWildcards()
667
    {
668
        return ['%', '_'];
669
    }
670
671
    /**
672
     * Returns the regular expression operator.
673
     *
674
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
675
     *
676
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
677
     */
678
    public function getRegexpExpression()
679
    {
680
        throw DBALException::notSupported(__METHOD__);
681
    }
682
683
    /**
684
     * Returns the global unique identifier expression.
685
     *
686
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
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
        throw DBALException::notSupported(__METHOD__);
695
    }
696
697
    /**
698
     * Returns the SQL snippet to get the average value of a column.
699
     *
700
     * @param string $column The column to use.
701
     *
702
     * @return string Generated SQL including an AVG aggregate function.
703
     */
704
    public function getAvgExpression($column)
705
    {
706
        return 'AVG(' . $column . ')';
707
    }
708
709
    /**
710
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
711
     *
712
     * If a '*' is used instead of a column the number of selected rows is returned.
713
     *
714
     * @param string|integer $column The column to use.
715
     *
716
     * @return string Generated SQL including a COUNT aggregate function.
717
     */
718
    public function getCountExpression($column)
719
    {
720
        return 'COUNT(' . $column . ')';
721
    }
722
723
    /**
724
     * Returns the SQL snippet to get the highest value of a column.
725
     *
726
     * @param string $column The column to use.
727
     *
728
     * @return string Generated SQL including a MAX aggregate function.
729
     */
730
    public function getMaxExpression($column)
731
    {
732
        return 'MAX(' . $column . ')';
733
    }
734
735
    /**
736
     * Returns the SQL snippet to get the lowest value of a column.
737
     *
738
     * @param string $column The column to use.
739
     *
740
     * @return string Generated SQL including a MIN aggregate function.
741
     */
742
    public function getMinExpression($column)
743
    {
744
        return 'MIN(' . $column . ')';
745
    }
746
747
    /**
748
     * Returns the SQL snippet to get the total sum of a column.
749
     *
750
     * @param string $column The column to use.
751
     *
752
     * @return string Generated SQL including a SUM aggregate function.
753
     */
754
    public function getSumExpression($column)
755
    {
756
        return 'SUM(' . $column . ')';
757
    }
758
759
    // scalar functions
760
761
    /**
762
     * Returns the SQL snippet to get the md5 sum of a field.
763
     *
764
     * Note: Not SQL92, but common functionality.
765
     *
766
     * @param string $column
767
     *
768
     * @return string
769
     */
770
    public function getMd5Expression($column)
771
    {
772
        return 'MD5(' . $column . ')';
773
    }
774
775
    /**
776
     * Returns the SQL snippet to get the length of a text field.
777
     *
778
     * @param string $column
779
     *
780
     * @return string
781
     */
782
    public function getLengthExpression($column)
783
    {
784
        return 'LENGTH(' . $column . ')';
785
    }
786
787
    /**
788
     * Returns the SQL snippet to get the squared value of a column.
789
     *
790
     * @param string $column The column to use.
791
     *
792
     * @return string Generated SQL including an SQRT aggregate function.
793
     */
794
    public function getSqrtExpression($column)
795
    {
796
        return 'SQRT(' . $column . ')';
797
    }
798
799
    /**
800
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
801
     *
802
     * @param string $column
803
     * @param int    $decimals
804
     *
805
     * @return string
806
     */
807
    public function getRoundExpression($column, $decimals = 0)
808
    {
809
        return 'ROUND(' . $column . ', ' . $decimals . ')';
810
    }
811
812
    /**
813
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
814
     *
815
     * @param string $expression1
816
     * @param string $expression2
817
     *
818
     * @return string
819
     */
820
    public function getModExpression($expression1, $expression2)
821
    {
822
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
823
    }
824
825
    /**
826
     * Returns the SQL snippet to trim a string.
827
     *
828
     * @param string      $str  The expression to apply the trim to.
829
     * @param int         $mode The position of the trim (leading/trailing/both).
830
     * @param string|bool $char The char to trim, has to be quoted already. Defaults to space.
831
     *
832
     * @return string
833
     */
834
    public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false)
835
    {
836
        $expression = '';
837
838
        switch ($mode) {
839
            case TrimMode::LEADING:
840
                $expression = 'LEADING ';
841
                break;
842
843
            case TrimMode::TRAILING:
844
                $expression = 'TRAILING ';
845
                break;
846
847
            case TrimMode::BOTH:
848
                $expression = 'BOTH ';
849
                break;
850
        }
851
852
        if ($char !== false) {
853
            $expression .= $char . ' ';
854
        }
855
856
        if ($mode || $char !== false) {
857
            $expression .= 'FROM ';
858
        }
859
860
        return 'TRIM(' . $expression . $str . ')';
861
    }
862
863
    /**
864
     * Returns the SQL snippet to trim trailing space characters from the expression.
865
     *
866
     * @param string $str Literal string or column name.
867
     *
868
     * @return string
869
     */
870
    public function getRtrimExpression($str)
871
    {
872
        return 'RTRIM(' . $str . ')';
873
    }
874
875
    /**
876
     * Returns the SQL snippet to trim leading space characters from the expression.
877
     *
878
     * @param string $str Literal string or column name.
879
     *
880
     * @return string
881
     */
882
    public function getLtrimExpression($str)
883
    {
884
        return 'LTRIM(' . $str . ')';
885
    }
886
887
    /**
888
     * Returns the SQL snippet to change all characters from the expression to uppercase,
889
     * according to the current character set mapping.
890
     *
891
     * @param string $str Literal string or column name.
892
     *
893
     * @return string
894
     */
895
    public function getUpperExpression($str)
896
    {
897
        return 'UPPER(' . $str . ')';
898
    }
899
900
    /**
901
     * Returns the SQL snippet to change all characters from the expression to lowercase,
902
     * according to the current character set mapping.
903
     *
904
     * @param string $str Literal string or column name.
905
     *
906
     * @return string
907
     */
908
    public function getLowerExpression($str)
909
    {
910
        return 'LOWER(' . $str . ')';
911
    }
912
913
    /**
914
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
915
     *
916
     * @param string   $str      Literal string.
917
     * @param string   $substr   Literal string to find.
918
     * @param int|bool $startPos Position to start at, beginning of string by default.
919
     *
920
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

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

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1092
     *
1093
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1094
     */
1095
    public function getDateDiffExpression($date1, $date2)
1096
    {
1097
        throw DBALException::notSupported(__METHOD__);
1098
    }
1099
1100
    /**
1101
     * Returns the SQL to add the number of given seconds to a date.
1102
     *
1103
     * @param string $date
1104
     * @param int    $seconds
1105
     *
1106
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1107
     *
1108
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1109
     */
1110
    public function getDateAddSecondsExpression($date, $seconds)
1111
    {
1112
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND);
1113
    }
1114
1115
    /**
1116
     * Returns the SQL to subtract the number of given seconds from a date.
1117
     *
1118
     * @param string $date
1119
     * @param int    $seconds
1120
     *
1121
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1122
     *
1123
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1124
     */
1125
    public function getDateSubSecondsExpression($date, $seconds)
1126
    {
1127
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND);
1128
    }
1129
1130
    /**
1131
     * Returns the SQL to add the number of given minutes to a date.
1132
     *
1133
     * @param string $date
1134
     * @param int    $minutes
1135
     *
1136
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1137
     *
1138
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1139
     */
1140
    public function getDateAddMinutesExpression($date, $minutes)
1141
    {
1142
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE);
1143
    }
1144
1145
    /**
1146
     * Returns the SQL to subtract the number of given minutes from a date.
1147
     *
1148
     * @param string $date
1149
     * @param int    $minutes
1150
     *
1151
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1152
     *
1153
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1154
     */
1155
    public function getDateSubMinutesExpression($date, $minutes)
1156
    {
1157
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE);
1158
    }
1159
1160
    /**
1161
     * Returns the SQL to add the number of given hours to a date.
1162
     *
1163
     * @param string $date
1164
     * @param int    $hours
1165
     *
1166
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1167
     *
1168
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1169
     */
1170
    public function getDateAddHourExpression($date, $hours)
1171
    {
1172
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR);
1173
    }
1174
1175
    /**
1176
     * Returns the SQL to subtract the number of given hours to a date.
1177
     *
1178
     * @param string $date
1179
     * @param int    $hours
1180
     *
1181
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1182
     *
1183
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1184
     */
1185
    public function getDateSubHourExpression($date, $hours)
1186
    {
1187
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR);
1188
    }
1189
1190
    /**
1191
     * Returns the SQL to add the number of given days to a date.
1192
     *
1193
     * @param string $date
1194
     * @param int    $days
1195
     *
1196
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1197
     *
1198
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1199
     */
1200
    public function getDateAddDaysExpression($date, $days)
1201
    {
1202
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY);
1203
    }
1204
1205
    /**
1206
     * Returns the SQL to subtract the number of given days to a date.
1207
     *
1208
     * @param string $date
1209
     * @param int    $days
1210
     *
1211
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1212
     *
1213
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1214
     */
1215
    public function getDateSubDaysExpression($date, $days)
1216
    {
1217
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY);
1218
    }
1219
1220
    /**
1221
     * Returns the SQL to add the number of given weeks to a date.
1222
     *
1223
     * @param string $date
1224
     * @param int    $weeks
1225
     *
1226
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1227
     *
1228
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1229
     */
1230
    public function getDateAddWeeksExpression($date, $weeks)
1231
    {
1232
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK);
1233
    }
1234
1235
    /**
1236
     * Returns the SQL to subtract the number of given weeks from a date.
1237
     *
1238
     * @param string $date
1239
     * @param int    $weeks
1240
     *
1241
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1242
     *
1243
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1244
     */
1245
    public function getDateSubWeeksExpression($date, $weeks)
1246
    {
1247
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK);
1248
    }
1249
1250
    /**
1251
     * Returns the SQL to add the number of given months to a date.
1252
     *
1253
     * @param string $date
1254
     * @param int    $months
1255
     *
1256
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1257
     *
1258
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1259
     */
1260
    public function getDateAddMonthExpression($date, $months)
1261
    {
1262
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH);
1263
    }
1264
1265
    /**
1266
     * Returns the SQL to subtract the number of given months to a date.
1267
     *
1268
     * @param string $date
1269
     * @param int    $months
1270
     *
1271
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1272
     *
1273
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1274
     */
1275
    public function getDateSubMonthExpression($date, $months)
1276
    {
1277
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH);
1278
    }
1279
1280
    /**
1281
     * Returns the SQL to add the number of given quarters to a date.
1282
     *
1283
     * @param string $date
1284
     * @param int    $quarters
1285
     *
1286
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1287
     *
1288
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1289
     */
1290
    public function getDateAddQuartersExpression($date, $quarters)
1291
    {
1292
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER);
1293
    }
1294
1295
    /**
1296
     * Returns the SQL to subtract the number of given quarters from a date.
1297
     *
1298
     * @param string $date
1299
     * @param int    $quarters
1300
     *
1301
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1302
     *
1303
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1304
     */
1305
    public function getDateSubQuartersExpression($date, $quarters)
1306
    {
1307
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER);
1308
    }
1309
1310
    /**
1311
     * Returns the SQL to add the number of given years to a date.
1312
     *
1313
     * @param string $date
1314
     * @param int    $years
1315
     *
1316
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1317
     *
1318
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1319
     */
1320
    public function getDateAddYearsExpression($date, $years)
1321
    {
1322
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR);
1323
    }
1324
1325
    /**
1326
     * Returns the SQL to subtract the number of given years from a date.
1327
     *
1328
     * @param string $date
1329
     * @param int    $years
1330
     *
1331
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1332
     *
1333
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1334
     */
1335
    public function getDateSubYearsExpression($date, $years)
1336
    {
1337
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR);
1338
    }
1339
1340
    /**
1341
     * Returns the SQL for a date arithmetic expression.
1342
     *
1343
     * @param string $date     The column or literal representing a date to perform the arithmetic operation on.
1344
     * @param string $operator The arithmetic operator (+ or -).
1345
     * @param int    $interval The interval that shall be calculated into the date.
1346
     * @param string $unit     The unit of the interval that shall be calculated into the date.
1347
     *                         One of the DATE_INTERVAL_UNIT_* constants.
1348
     *
1349
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1350
     *
1351
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1352
     */
1353
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
1354
    {
1355
        throw DBALException::notSupported(__METHOD__);
1356
    }
1357
1358
    /**
1359
     * Returns the SQL bit AND comparison expression.
1360
     *
1361
     * @param string $value1
1362
     * @param string $value2
1363
     *
1364
     * @return string
1365
     */
1366
    public function getBitAndComparisonExpression($value1, $value2)
1367
    {
1368
        return '(' . $value1 . ' & ' . $value2 . ')';
1369
    }
1370
1371
    /**
1372
     * Returns the SQL bit OR comparison expression.
1373
     *
1374
     * @param string $value1
1375
     * @param string $value2
1376
     *
1377
     * @return string
1378
     */
1379
    public function getBitOrComparisonExpression($value1, $value2)
1380
    {
1381
        return '(' . $value1 . ' | ' . $value2 . ')';
1382
    }
1383
1384
    /**
1385
     * Returns the FOR UPDATE expression.
1386
     *
1387
     * @return string
1388
     */
1389
    public function getForUpdateSQL()
1390
    {
1391
        return 'FOR UPDATE';
1392
    }
1393
1394
    /**
1395
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1396
     *
1397
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1398
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1399
     *                             be appended to the FROM clause.
1400
     *
1401
     * @return string
1402
     */
1403
    public function appendLockHint($fromClause, $lockMode)
1404
    {
1405
        return $fromClause;
1406
    }
1407
1408
    /**
1409
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1410
     *
1411
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1412
     * vendors allow to lighten this constraint up to be a real read lock.
1413
     *
1414
     * @return string
1415
     */
1416
    public function getReadLockSQL()
1417
    {
1418
        return $this->getForUpdateSQL();
1419
    }
1420
1421
    /**
1422
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1423
     *
1424
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1425
     *
1426
     * @return string
1427
     */
1428
    public function getWriteLockSQL()
1429
    {
1430
        return $this->getForUpdateSQL();
1431
    }
1432
1433
    /**
1434
     * Returns the SQL snippet to drop an existing database.
1435
     *
1436
     * @param string $database The name of the database that should be dropped.
1437
     *
1438
     * @return string
1439
     */
1440
    public function getDropDatabaseSQL($database)
1441
    {
1442
        return 'DROP DATABASE ' . $database;
1443
    }
1444
1445
    /**
1446
     * Returns the SQL snippet to drop an existing table.
1447
     *
1448
     * @param \Doctrine\DBAL\Schema\Table|string $table
1449
     *
1450
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1451
     *
1452
     * @throws \InvalidArgumentException
1453
     */
1454
    public function getDropTableSQL($table)
1455
    {
1456
        $tableArg = $table;
1457
1458
        if ($table instanceof Table) {
1459
            $table = $table->getQuotedName($this);
1460
        } elseif (!is_string($table)) {
1461
            throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1462
        }
1463
1464
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1465
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1466
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1467
1468
            if ($eventArgs->isDefaultPrevented()) {
1469
                return $eventArgs->getSql();
1470
            }
1471
        }
1472
1473
        return 'DROP TABLE ' . $table;
1474
    }
1475
1476
    /**
1477
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1478
     *
1479
     * @param \Doctrine\DBAL\Schema\Table|string $table
1480
     *
1481
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1482
     */
1483
    public function getDropTemporaryTableSQL($table)
1484
    {
1485
        return $this->getDropTableSQL($table);
1486
    }
1487
1488
    /**
1489
     * Returns the SQL to drop an index from a table.
1490
     *
1491
     * @param \Doctrine\DBAL\Schema\Index|string $index
1492
     * @param \Doctrine\DBAL\Schema\Table|string $table
0 ignored issues
show
Documentation introduced by
Should the type for parameter $table not be Table|string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1493
     *
1494
     * @return string
1495
     *
1496
     * @throws \InvalidArgumentException
1497
     */
1498
    public function getDropIndexSQL($index, $table = null)
1499
    {
1500
        if ($index instanceof Index) {
1501
            $index = $index->getQuotedName($this);
1502
        } elseif (!is_string($index)) {
1503
            throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1504
        }
1505
1506
        return 'DROP INDEX ' . $index;
1507
    }
1508
1509
    /**
1510
     * Returns the SQL to drop a constraint.
1511
     *
1512
     * @param \Doctrine\DBAL\Schema\Constraint|string $constraint
1513
     * @param \Doctrine\DBAL\Schema\Table|string      $table
1514
     *
1515
     * @return string
1516
     */
1517
    public function getDropConstraintSQL($constraint, $table)
1518
    {
1519
        if (! $constraint instanceof Constraint) {
1520
            $constraint = new Identifier($constraint);
1521
        }
1522
1523
        if (! $table instanceof Table) {
1524
            $table = new Identifier($table);
1525
        }
1526
1527
        $constraint = $constraint->getQuotedName($this);
1528
        $table = $table->getQuotedName($this);
1529
1530
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1531
    }
1532
1533
    /**
1534
     * Returns the SQL to drop a foreign key.
1535
     *
1536
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint|string $foreignKey
1537
     * @param \Doctrine\DBAL\Schema\Table|string                $table
1538
     *
1539
     * @return string
1540
     */
1541
    public function getDropForeignKeySQL($foreignKey, $table)
1542
    {
1543
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1544
            $foreignKey = new Identifier($foreignKey);
1545
        }
1546
1547
        if (! $table instanceof Table) {
1548
            $table = new Identifier($table);
1549
        }
1550
1551
        $foreignKey = $foreignKey->getQuotedName($this);
1552
        $table = $table->getQuotedName($this);
1553
1554
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1555
    }
1556
1557
    /**
1558
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1559
     * on this platform.
1560
     *
1561
     * @param \Doctrine\DBAL\Schema\Table $table
1562
     * @param int                         $createFlags
1563
     *
1564
     * @return array The sequence of SQL statements.
1565
     *
1566
     * @throws \Doctrine\DBAL\DBALException
1567
     * @throws \InvalidArgumentException
1568
     */
1569
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1570
    {
1571
        if ( ! is_int($createFlags)) {
1572
            throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
1573
        }
1574
1575
        if (count($table->getColumns()) === 0) {
1576
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1577
        }
1578
1579
        $tableName = $table->getQuotedName($this);
1580
        $options = $table->getOptions();
1581
        $options['uniqueConstraints'] = [];
1582
        $options['indexes'] = [];
1583
        $options['primary'] = [];
1584
1585
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1586
            foreach ($table->getIndexes() as $index) {
1587
                /* @var $index Index */
1588
                if ($index->isPrimary()) {
1589
                    $options['primary']       = $index->getQuotedColumns($this);
1590
                    $options['primary_index'] = $index;
1591
                } else {
1592
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1593
                }
1594
            }
1595
        }
1596
1597
        $columnSql = [];
1598
        $columns = [];
1599
1600
        foreach ($table->getColumns() as $column) {
1601
            /* @var \Doctrine\DBAL\Schema\Column $column */
1602
1603
            if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) {
1604
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1605
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1606
1607
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1608
1609
                if ($eventArgs->isDefaultPrevented()) {
1610
                    continue;
1611
                }
1612
            }
1613
1614
            $columnData = $column->toArray();
1615
            $columnData['name'] = $column->getQuotedName($this);
1616
            $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false;
1617
            $columnData['comment'] = $this->getColumnComment($column);
1618
1619
            if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) {
1620
                $columnData['length'] = 255;
1621
            }
1622
1623
            if (in_array($column->getName(), $options['primary'])) {
1624
                $columnData['primary'] = true;
1625
            }
1626
1627
            $columns[$columnData['name']] = $columnData;
1628
        }
1629
1630
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1631
            $options['foreignKeys'] = [];
1632
            foreach ($table->getForeignKeys() as $fkConstraint) {
1633
                $options['foreignKeys'][] = $fkConstraint;
1634
            }
1635
        }
1636
1637
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
1638
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1639
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1640
1641
            if ($eventArgs->isDefaultPrevented()) {
1642
                return array_merge($eventArgs->getSql(), $columnSql);
1643
            }
1644
        }
1645
1646
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1647
        if ($this->supportsCommentOnStatement()) {
1648
            foreach ($table->getColumns() as $column) {
1649
                $comment = $this->getColumnComment($column);
1650
1651
                if (null !== $comment && '' !== $comment) {
1652
                    $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1653
                }
1654
            }
1655
        }
1656
1657
        return array_merge($sql, $columnSql);
1658
    }
1659
1660
    /**
1661
     * @param string $tableName
1662
     * @param string $columnName
1663
     * @param string $comment
1664
     *
1665
     * @return string
1666
     */
1667
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
1668
    {
1669
        $tableName = new Identifier($tableName);
1670
        $columnName = new Identifier($columnName);
1671
        $comment = $this->quoteStringLiteral($comment);
1672
1673
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . "." . $columnName->getQuotedName($this) .
1674
            " IS " . $comment;
1675
    }
1676
1677
    /**
1678
     * Returns the SQL to create inline comment on a column.
1679
     *
1680
     * @param string $comment
1681
     *
1682
     * @return string
1683
     *
1684
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1685
     */
1686
    public function getInlineColumnCommentSQL($comment)
1687
    {
1688
        if (! $this->supportsInlineColumnComments()) {
1689
            throw DBALException::notSupported(__METHOD__);
1690
        }
1691
1692
        return "COMMENT " . $this->quoteStringLiteral($comment);
1693
    }
1694
1695
    /**
1696
     * Returns the SQL used to create a table.
1697
     *
1698
     * @param string $tableName
1699
     * @param array  $columns
1700
     * @param array  $options
1701
     *
1702
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1703
     */
1704
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1705
    {
1706
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1707
1708
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1709
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1710
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1711
            }
1712
        }
1713
1714
        if (isset($options['primary']) && ! empty($options['primary'])) {
1715
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1716
        }
1717
1718
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1719
            foreach ($options['indexes'] as $index => $definition) {
1720
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1721
            }
1722
        }
1723
1724
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1725
1726
        $check = $this->getCheckDeclarationSQL($columns);
1727
        if ( ! empty($check)) {
1728
            $query .= ', ' . $check;
1729
        }
1730
        $query .= ')';
1731
1732
        $sql[] = $query;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1733
1734
        if (isset($options['foreignKeys'])) {
1735
            foreach ((array) $options['foreignKeys'] as $definition) {
1736
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1737
            }
1738
        }
1739
1740
        return $sql;
1741
    }
1742
1743
    /**
1744
     * @return string
1745
     */
1746
    public function getCreateTemporaryTableSnippetSQL()
1747
    {
1748
        return "CREATE TEMPORARY TABLE";
1749
    }
1750
1751
    /**
1752
     * Returns the SQL to create a sequence on this platform.
1753
     *
1754
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1755
     *
1756
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1757
     *
1758
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1759
     */
1760
    public function getCreateSequenceSQL(Sequence $sequence)
1761
    {
1762
        throw DBALException::notSupported(__METHOD__);
1763
    }
1764
1765
    /**
1766
     * Returns the SQL to change a sequence on this platform.
1767
     *
1768
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1769
     *
1770
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

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

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1900
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1901
     */
1902
    public function getCreateSchemaSQL($schemaName)
1903
    {
1904
        throw DBALException::notSupported(__METHOD__);
1905
    }
1906
1907
    /**
1908
     * Quotes a string so that it can be safely used as a table or column name,
1909
     * even if it is a reserved word of the platform. This also detects identifier
1910
     * chains separated by dot and quotes them independently.
1911
     *
1912
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1913
     * you SHOULD use them. In general, they end up causing way more
1914
     * problems than they solve.
1915
     *
1916
     * @param string $str The identifier name to be quoted.
1917
     *
1918
     * @return string The quoted identifier string.
1919
     */
1920
    public function quoteIdentifier($str)
1921
    {
1922
        if (strpos($str, ".") !== false) {
1923
            $parts = array_map([$this, "quoteSingleIdentifier"], explode(".", $str));
1924
1925
            return implode(".", $parts);
1926
        }
1927
1928
        return $this->quoteSingleIdentifier($str);
1929
    }
1930
1931
    /**
1932
     * Quotes a single identifier (no dot chain separation).
1933
     *
1934
     * @param string $str The identifier name to be quoted.
1935
     *
1936
     * @return string The quoted identifier string.
1937
     */
1938
    public function quoteSingleIdentifier($str)
1939
    {
1940
        $c = $this->getIdentifierQuoteCharacter();
1941
1942
        return $c . str_replace($c, $c.$c, $str) . $c;
1943
    }
1944
1945
    /**
1946
     * Returns the SQL to create a new foreign key.
1947
     *
1948
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key constraint.
1949
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
1950
     *
1951
     * @return string
1952
     */
1953
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1954
    {
1955
        if ($table instanceof Table) {
1956
            $table = $table->getQuotedName($this);
1957
        }
1958
1959
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1960
1961
        return $query;
1962
    }
1963
1964
    /**
1965
     * Gets the SQL statements for altering an existing table.
1966
     *
1967
     * This method returns an array of SQL statements, since some platforms need several statements.
1968
     *
1969
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1970
     *
1971
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1972
     *
1973
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1974
     */
1975
    public function getAlterTableSQL(TableDiff $diff)
1976
    {
1977
        throw DBALException::notSupported(__METHOD__);
1978
    }
1979
1980
    /**
1981
     * @param \Doctrine\DBAL\Schema\Column    $column
1982
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1983
     * @param array                           $columnSql
1984
     *
1985
     * @return bool
1986
     */
1987
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
1988
    {
1989
        if (null === $this->_eventManager) {
1990
            return false;
1991
        }
1992
1993
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1994
            return false;
1995
        }
1996
1997
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1998
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1999
2000
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2001
2002
        return $eventArgs->isDefaultPrevented();
2003
    }
2004
2005
    /**
2006
     * @param \Doctrine\DBAL\Schema\Column    $column
2007
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2008
     * @param array                           $columnSql
2009
     *
2010
     * @return bool
2011
     */
2012
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
2013
    {
2014
        if (null === $this->_eventManager) {
2015
            return false;
2016
        }
2017
2018
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
2019
            return false;
2020
        }
2021
2022
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
2023
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
2024
2025
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2026
2027
        return $eventArgs->isDefaultPrevented();
2028
    }
2029
2030
    /**
2031
     * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff
2032
     * @param \Doctrine\DBAL\Schema\TableDiff  $diff
2033
     * @param array                            $columnSql
2034
     *
2035
     * @return bool
2036
     */
2037
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
2038
    {
2039
        if (null === $this->_eventManager) {
2040
            return false;
2041
        }
2042
2043
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
2044
            return false;
2045
        }
2046
2047
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
2048
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
2049
2050
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2051
2052
        return $eventArgs->isDefaultPrevented();
2053
    }
2054
2055
    /**
2056
     * @param string                          $oldColumnName
2057
     * @param \Doctrine\DBAL\Schema\Column    $column
2058
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2059
     * @param array                           $columnSql
2060
     *
2061
     * @return bool
2062
     */
2063
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
2064
    {
2065
        if (null === $this->_eventManager) {
2066
            return false;
2067
        }
2068
2069
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2070
            return false;
2071
        }
2072
2073
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2074
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2075
2076
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2077
2078
        return $eventArgs->isDefaultPrevented();
2079
    }
2080
2081
    /**
2082
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2083
     * @param array                           $sql
2084
     *
2085
     * @return bool
2086
     */
2087
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
2088
    {
2089
        if (null === $this->_eventManager) {
2090
            return false;
2091
        }
2092
2093
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2094
            return false;
2095
        }
2096
2097
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2098
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2099
2100
        $sql = array_merge($sql, $eventArgs->getSql());
2101
2102
        return $eventArgs->isDefaultPrevented();
2103
    }
2104
2105
    /**
2106
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2107
     *
2108
     * @return array
2109
     */
2110
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2111
    {
2112
        $tableName = $diff->getName($this)->getQuotedName($this);
2113
2114
        $sql = [];
2115
        if ($this->supportsForeignKeyConstraints()) {
2116
            foreach ($diff->removedForeignKeys as $foreignKey) {
2117
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2118
            }
2119
            foreach ($diff->changedForeignKeys as $foreignKey) {
2120
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2121
            }
2122
        }
2123
2124
        foreach ($diff->removedIndexes as $index) {
2125
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2126
        }
2127
        foreach ($diff->changedIndexes as $index) {
2128
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2129
        }
2130
2131
        return $sql;
2132
    }
2133
2134
    /**
2135
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2136
     *
2137
     * @return array
2138
     */
2139
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2140
    {
2141
        $tableName = (false !== $diff->newName)
2142
            ? $diff->getNewName()->getQuotedName($this)
2143
            : $diff->getName($this)->getQuotedName($this);
2144
2145
        $sql = [];
2146
2147
        if ($this->supportsForeignKeyConstraints()) {
2148
            foreach ($diff->addedForeignKeys as $foreignKey) {
2149
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2150
            }
2151
2152
            foreach ($diff->changedForeignKeys as $foreignKey) {
2153
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2154
            }
2155
        }
2156
2157
        foreach ($diff->addedIndexes as $index) {
2158
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2159
        }
2160
2161
        foreach ($diff->changedIndexes as $index) {
2162
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2163
        }
2164
2165
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2166
            $oldIndexName = new Identifier($oldIndexName);
2167
            $sql          = array_merge(
2168
                $sql,
2169
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2170
            );
2171
        }
2172
2173
        return $sql;
2174
    }
2175
2176
    /**
2177
     * Returns the SQL for renaming an index on a table.
2178
     *
2179
     * @param string                      $oldIndexName The name of the index to rename from.
2180
     * @param \Doctrine\DBAL\Schema\Index $index        The definition of the index to rename to.
2181
     * @param string                      $tableName    The table to rename the given index on.
2182
     *
2183
     * @return array The sequence of SQL statements for renaming the given index.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2184
     */
2185
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2186
    {
2187
        return [
2188
            $this->getDropIndexSQL($oldIndexName, $tableName),
2189
            $this->getCreateIndexSQL($index, $tableName)
2190
        ];
2191
    }
2192
2193
    /**
2194
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2195
     *
2196
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2197
     *
2198
     * @return array
2199
     */
2200
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2201
    {
2202
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2203
    }
2204
2205
    /**
2206
     * Gets declaration of a number of fields in bulk.
2207
     *
2208
     * @param array $fields A multidimensional associative array.
2209
     *                      The first dimension determines the field name, while the second
2210
     *                      dimension is keyed with the name of the properties
2211
     *                      of the field being declared as array indexes. Currently, the types
2212
     *                      of supported field properties are as follows:
2213
     *
2214
     *      length
2215
     *          Integer value that determines the maximum length of the text
2216
     *          field. If this argument is missing the field should be
2217
     *          declared to have the longest length allowed by the DBMS.
2218
     *
2219
     *      default
2220
     *          Text value to be used as default for this field.
2221
     *
2222
     *      notnull
2223
     *          Boolean flag that indicates whether this field is constrained
2224
     *          to not be set to null.
2225
     *      charset
2226
     *          Text value with the default CHARACTER SET for this field.
2227
     *      collation
2228
     *          Text value with the default COLLATION for this field.
2229
     *      unique
2230
     *          unique constraint
2231
     *
2232
     * @return string
2233
     */
2234
    public function getColumnDeclarationListSQL(array $fields)
2235
    {
2236
        $queryFields = [];
2237
2238
        foreach ($fields as $fieldName => $field) {
2239
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2240
        }
2241
2242
        return implode(', ', $queryFields);
2243
    }
2244
2245
    /**
2246
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2247
     * field to be used in statements like CREATE TABLE.
2248
     *
2249
     * @param string $name  The name the field to be declared.
2250
     * @param array  $field An associative array with the name of the properties
2251
     *                      of the field being declared as array indexes. Currently, the types
2252
     *                      of supported field properties are as follows:
2253
     *
2254
     *      length
2255
     *          Integer value that determines the maximum length of the text
2256
     *          field. If this argument is missing the field should be
2257
     *          declared to have the longest length allowed by the DBMS.
2258
     *
2259
     *      default
2260
     *          Text value to be used as default for this field.
2261
     *
2262
     *      notnull
2263
     *          Boolean flag that indicates whether this field is constrained
2264
     *          to not be set to null.
2265
     *      charset
2266
     *          Text value with the default CHARACTER SET for this field.
2267
     *      collation
2268
     *          Text value with the default COLLATION for this field.
2269
     *      unique
2270
     *          unique constraint
2271
     *      check
2272
     *          column check constraint
2273
     *      columnDefinition
2274
     *          a string that defines the complete column
2275
     *
2276
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2277
     */
2278
    public function getColumnDeclarationSQL($name, array $field)
2279
    {
2280
        if (isset($field['columnDefinition'])) {
2281
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2282
        } else {
2283
            $default = $this->getDefaultValueDeclarationSQL($field);
2284
2285
            $charset = (isset($field['charset']) && $field['charset']) ?
2286
                ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2287
2288
            $collation = (isset($field['collation']) && $field['collation']) ?
2289
                ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2290
2291
            $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
2292
2293
            $unique = (isset($field['unique']) && $field['unique']) ?
2294
                ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2295
2296
            $check = (isset($field['check']) && $field['check']) ?
2297
                ' ' . $field['check'] : '';
2298
2299
            $typeDecl = $field['type']->getSQLDeclaration($field, $this);
2300
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2301
2302
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2303
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2304
            }
2305
        }
2306
2307
        return $name . ' ' . $columnDef;
2308
    }
2309
2310
    /**
2311
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2312
     *
2313
     * @param array $columnDef
2314
     *
2315
     * @return string
2316
     */
2317
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2318
    {
2319
        $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
2320
            ? 10 : $columnDef['precision'];
2321
        $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
2322
            ? 0 : $columnDef['scale'];
2323
2324
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2325
    }
2326
2327
    /**
2328
     * Obtains DBMS specific SQL code portion needed to set a default value
2329
     * declaration to be used in statements like CREATE TABLE.
2330
     *
2331
     * @param array $field The field definition array.
2332
     *
2333
     * @return string DBMS specific SQL code portion needed to set a default value.
2334
     */
2335
    public function getDefaultValueDeclarationSQL($field)
2336
    {
2337
        if ( ! isset($field['default'])) {
2338
            return empty($field['notnull']) ? ' DEFAULT NULL' : '';
2339
        }
2340
2341
        $default = $field['default'];
2342
2343
        if ( ! isset($field['type'])) {
2344
            return " DEFAULT '" . $default . "'";
2345
        }
2346
2347
        $type = $field['type'];
2348
2349
        if ($type instanceof Types\PhpIntegerMappingType) {
2350
            return ' DEFAULT ' . $default;
2351
        }
2352
2353
        if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
2354
            return ' DEFAULT ' . $this->getCurrentTimestampSQL();
2355
        }
2356
2357
        if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
2358
            return ' DEFAULT ' . $this->getCurrentTimeSQL();
2359
        }
2360
2361
        if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
2362
            return ' DEFAULT ' . $this->getCurrentDateSQL();
2363
        }
2364
2365
        if ($type instanceof Types\BooleanType) {
2366
            return " DEFAULT '" . $this->convertBooleans($default) . "'";
2367
        }
2368
2369
        return " DEFAULT '" . $default . "'";
2370
    }
2371
2372
    /**
2373
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2374
     * declaration to be used in statements like CREATE TABLE.
2375
     *
2376
     * @param array $definition The check definition.
2377
     *
2378
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2379
     */
2380
    public function getCheckDeclarationSQL(array $definition)
2381
    {
2382
        $constraints = [];
2383
        foreach ($definition as $field => $def) {
2384
            if (is_string($def)) {
2385
                $constraints[] = 'CHECK (' . $def . ')';
2386
            } else {
2387
                if (isset($def['min'])) {
2388
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2389
                }
2390
2391
                if (isset($def['max'])) {
2392
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2393
                }
2394
            }
2395
        }
2396
2397
        return implode(', ', $constraints);
2398
    }
2399
2400
    /**
2401
     * Obtains DBMS specific SQL code portion needed to set a unique
2402
     * constraint declaration to be used in statements like CREATE TABLE.
2403
     *
2404
     * @param string                      $name  The name of the unique constraint.
2405
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2406
     *
2407
     * @return string DBMS specific SQL code portion needed to set a constraint.
2408
     *
2409
     * @throws \InvalidArgumentException
2410
     */
2411
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
2412
    {
2413
        $columns = $index->getQuotedColumns($this);
2414
        $name = new Identifier($name);
2415
2416
        if (count($columns) === 0) {
2417
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2418
        }
2419
2420
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2421
            . $this->getIndexFieldDeclarationListSQL($columns)
2422
            . ')' . $this->getPartialIndexSQL($index);
2423
    }
2424
2425
    /**
2426
     * Obtains DBMS specific SQL code portion needed to set an index
2427
     * declaration to be used in statements like CREATE TABLE.
2428
     *
2429
     * @param string                      $name  The name of the index.
2430
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2431
     *
2432
     * @return string DBMS specific SQL code portion needed to set an index.
2433
     *
2434
     * @throws \InvalidArgumentException
2435
     */
2436
    public function getIndexDeclarationSQL($name, Index $index)
2437
    {
2438
        $columns = $index->getQuotedColumns($this);
2439
        $name = new Identifier($name);
2440
2441
        if (count($columns) === 0) {
2442
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2443
        }
2444
2445
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2446
            . $this->getIndexFieldDeclarationListSQL($columns)
2447
            . ')' . $this->getPartialIndexSQL($index);
2448
    }
2449
2450
    /**
2451
     * Obtains SQL code portion needed to create a custom column,
2452
     * e.g. when a field has the "columnDefinition" keyword.
2453
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2454
     *
2455
     * @param array $columnDef
2456
     *
2457
     * @return string
2458
     */
2459
    public function getCustomTypeDeclarationSQL(array $columnDef)
2460
    {
2461
        return $columnDef['columnDefinition'];
2462
    }
2463
2464
    /**
2465
     * Obtains DBMS specific SQL code portion needed to set an index
2466
     * declaration to be used in statements like CREATE TABLE.
2467
     *
2468
     * @param array $fields
2469
     *
2470
     * @return string
2471
     */
2472
    public function getIndexFieldDeclarationListSQL(array $fields)
2473
    {
2474
        $ret = [];
2475
2476
        foreach ($fields as $field => $definition) {
2477
            if (is_array($definition)) {
2478
                $ret[] = $field;
2479
            } else {
2480
                $ret[] = $definition;
2481
            }
2482
        }
2483
2484
        return implode(', ', $ret);
2485
    }
2486
2487
    /**
2488
     * Returns the required SQL string that fits between CREATE ... TABLE
2489
     * to create the table as a temporary table.
2490
     *
2491
     * Should be overridden in driver classes to return the correct string for the
2492
     * specific database type.
2493
     *
2494
     * The default is to return the string "TEMPORARY" - this will result in a
2495
     * SQL error for any database that does not support temporary tables, or that
2496
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2497
     *
2498
     * @return string The string required to be placed between "CREATE" and "TABLE"
2499
     *                to generate a temporary table, if possible.
2500
     */
2501
    public function getTemporaryTableSQL()
2502
    {
2503
        return 'TEMPORARY';
2504
    }
2505
2506
    /**
2507
     * Some vendors require temporary table names to be qualified specially.
2508
     *
2509
     * @param string $tableName
2510
     *
2511
     * @return string
2512
     */
2513
    public function getTemporaryTableName($tableName)
2514
    {
2515
        return $tableName;
2516
    }
2517
2518
    /**
2519
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2520
     * of a field declaration to be used in statements like CREATE TABLE.
2521
     *
2522
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2523
     *
2524
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2525
     *                of a field declaration.
2526
     */
2527
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2528
    {
2529
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2530
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2531
2532
        return $sql;
2533
    }
2534
2535
    /**
2536
     * Returns the FOREIGN KEY query section dealing with non-standard options
2537
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2538
     *
2539
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key definition.
2540
     *
2541
     * @return string
2542
     */
2543
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2544
    {
2545
        $query = '';
2546
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2547
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2548
        }
2549
        if ($foreignKey->hasOption('onDelete')) {
2550
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2551
        }
2552
2553
        return $query;
2554
    }
2555
2556
    /**
2557
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2558
     *
2559
     * @param string $action The foreign key referential action.
2560
     *
2561
     * @return string
2562
     *
2563
     * @throws \InvalidArgumentException if unknown referential action given
2564
     */
2565
    public function getForeignKeyReferentialActionSQL($action)
2566
    {
2567
        $upper = strtoupper($action);
2568
        switch ($upper) {
2569
            case 'CASCADE':
2570
            case 'SET NULL':
2571
            case 'NO ACTION':
2572
            case 'RESTRICT':
2573
            case 'SET DEFAULT':
2574
                return $upper;
2575
            default:
2576
                throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper);
2577
        }
2578
    }
2579
2580
    /**
2581
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2582
     * of a field declaration to be used in statements like CREATE TABLE.
2583
     *
2584
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2585
     *
2586
     * @return string
2587
     *
2588
     * @throws \InvalidArgumentException
2589
     */
2590
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2591
    {
2592
        $sql = '';
2593
        if (strlen($foreignKey->getName())) {
2594
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2595
        }
2596
        $sql .= 'FOREIGN KEY (';
2597
2598
        if (count($foreignKey->getLocalColumns()) === 0) {
2599
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
2600
        }
2601
        if (count($foreignKey->getForeignColumns()) === 0) {
2602
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
2603
        }
2604
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2605
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2606
        }
2607
2608
        $sql .= implode(', ', $foreignKey->getQuotedLocalColumns($this))
2609
            . ') REFERENCES '
2610
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2611
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2612
2613
        return $sql;
2614
    }
2615
2616
    /**
2617
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2618
     * of a field declaration to be used in statements like CREATE TABLE.
2619
     *
2620
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2621
     *                of a field declaration.
2622
     */
2623
    public function getUniqueFieldDeclarationSQL()
2624
    {
2625
        return 'UNIQUE';
2626
    }
2627
2628
    /**
2629
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2630
     * of a field declaration to be used in statements like CREATE TABLE.
2631
     *
2632
     * @param string $charset The name of the charset.
2633
     *
2634
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2635
     *                of a field declaration.
2636
     */
2637
    public function getColumnCharsetDeclarationSQL($charset)
0 ignored issues
show
Unused Code introduced by
The parameter $charset is not used and could be removed.

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

Loading history...
2638
    {
2639
        return '';
2640
    }
2641
2642
    /**
2643
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2644
     * of a field declaration to be used in statements like CREATE TABLE.
2645
     *
2646
     * @param string $collation The name of the collation.
2647
     *
2648
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2649
     *                of a field declaration.
2650
     */
2651
    public function getColumnCollationDeclarationSQL($collation)
2652
    {
2653
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2654
    }
2655
2656
    /**
2657
     * Whether the platform prefers sequences for ID generation.
2658
     * Subclasses should override this method to return TRUE if they prefer sequences.
2659
     *
2660
     * @return bool
2661
     */
2662
    public function prefersSequences()
2663
    {
2664
        return false;
2665
    }
2666
2667
    /**
2668
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2669
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2670
     *
2671
     * @return bool
2672
     */
2673
    public function prefersIdentityColumns()
2674
    {
2675
        return false;
2676
    }
2677
2678
    /**
2679
     * Some platforms need the boolean values to be converted.
2680
     *
2681
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2682
     *
2683
     * Note: if the input is not a boolean the original input might be returned.
2684
     *
2685
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2686
     * This method should handle the literal case
2687
     *
2688
     * @param mixed $item A boolean or an array of them.
2689
     *
2690
     * @return mixed A boolean database value or an array of them.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use object|integer|double|string|null|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2691
     */
2692
    public function convertBooleans($item)
2693
    {
2694
        if (is_array($item)) {
2695
            foreach ($item as $k => $value) {
2696
                if (is_bool($value)) {
2697
                    $item[$k] = (int) $value;
2698
                }
2699
            }
2700
        } elseif (is_bool($item)) {
2701
            $item = (int) $item;
2702
        }
2703
2704
        return $item;
2705
    }
2706
2707
    /**
2708
     * Some platforms have boolean literals that needs to be correctly converted
2709
     *
2710
     * The default conversion tries to convert value into bool "(bool)$item"
2711
     *
2712
     * @param mixed $item
2713
     *
2714
     * @return bool|null
2715
     */
2716
    public function convertFromBoolean($item)
2717
    {
2718
        return null === $item ? null: (bool) $item ;
2719
    }
2720
2721
    /**
2722
     * This method should handle the prepared statements case. When there is no
2723
     * distinction, it's OK to use the same method.
2724
     *
2725
     * Note: if the input is not a boolean the original input might be returned.
2726
     *
2727
     * @param mixed $item A boolean or an array of them.
2728
     *
2729
     * @return mixed A boolean database value or an array of them.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use object|integer|double|string|null|array.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2730
     */
2731
    public function convertBooleansToDatabaseValue($item)
2732
    {
2733
        return $this->convertBooleans($item);
2734
    }
2735
2736
    /**
2737
     * Returns the SQL specific for the platform to get the current date.
2738
     *
2739
     * @return string
2740
     */
2741
    public function getCurrentDateSQL()
2742
    {
2743
        return 'CURRENT_DATE';
2744
    }
2745
2746
    /**
2747
     * Returns the SQL specific for the platform to get the current time.
2748
     *
2749
     * @return string
2750
     */
2751
    public function getCurrentTimeSQL()
2752
    {
2753
        return 'CURRENT_TIME';
2754
    }
2755
2756
    /**
2757
     * Returns the SQL specific for the platform to get the current timestamp
2758
     *
2759
     * @return string
2760
     */
2761
    public function getCurrentTimestampSQL()
2762
    {
2763
        return 'CURRENT_TIMESTAMP';
2764
    }
2765
2766
    /**
2767
     * Returns the SQL for a given transaction isolation level Connection constant.
2768
     *
2769
     * @param int $level
2770
     *
2771
     * @return string
2772
     *
2773
     * @throws \InvalidArgumentException
2774
     */
2775
    protected function _getTransactionIsolationLevelSQL($level)
2776
    {
2777
        switch ($level) {
2778
            case TransactionIsolationLevel::READ_UNCOMMITTED:
2779
                return 'READ UNCOMMITTED';
2780
            case TransactionIsolationLevel::READ_COMMITTED:
2781
                return 'READ COMMITTED';
2782
            case TransactionIsolationLevel::REPEATABLE_READ:
2783
                return 'REPEATABLE READ';
2784
            case TransactionIsolationLevel::SERIALIZABLE:
2785
                return 'SERIALIZABLE';
2786
            default:
2787
                throw new \InvalidArgumentException('Invalid isolation level:' . $level);
2788
        }
2789
    }
2790
2791
    /**
2792
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2793
     *
2794
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2795
     */
2796
    public function getListDatabasesSQL()
2797
    {
2798
        throw DBALException::notSupported(__METHOD__);
2799
    }
2800
2801
    /**
2802
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2803
     *
2804
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2805
     *
2806
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2807
     */
2808
    public function getListNamespacesSQL()
2809
    {
2810
        throw DBALException::notSupported(__METHOD__);
2811
    }
2812
2813
    /**
2814
     * @param string $database
2815
     *
2816
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2817
     *
2818
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2819
     */
2820
    public function getListSequencesSQL($database)
2821
    {
2822
        throw DBALException::notSupported(__METHOD__);
2823
    }
2824
2825
    /**
2826
     * @param string $table
2827
     *
2828
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2829
     *
2830
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2831
     */
2832
    public function getListTableConstraintsSQL($table)
2833
    {
2834
        throw DBALException::notSupported(__METHOD__);
2835
    }
2836
2837
    /**
2838
     * @param string      $table
2839
     * @param string|null $database
2840
     *
2841
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2842
     *
2843
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2844
     */
2845
    public function getListTableColumnsSQL($table, $database = null)
2846
    {
2847
        throw DBALException::notSupported(__METHOD__);
2848
    }
2849
2850
    /**
2851
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2852
     *
2853
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2854
     */
2855
    public function getListTablesSQL()
2856
    {
2857
        throw DBALException::notSupported(__METHOD__);
2858
    }
2859
2860
    /**
2861
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2862
     *
2863
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2864
     */
2865
    public function getListUsersSQL()
2866
    {
2867
        throw DBALException::notSupported(__METHOD__);
2868
    }
2869
2870
    /**
2871
     * Returns the SQL to list all views of a database or user.
2872
     *
2873
     * @param string $database
2874
     *
2875
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2876
     *
2877
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2878
     */
2879
    public function getListViewsSQL($database)
2880
    {
2881
        throw DBALException::notSupported(__METHOD__);
2882
    }
2883
2884
    /**
2885
     * Returns the list of indexes for the current database.
2886
     *
2887
     * The current database parameter is optional but will always be passed
2888
     * when using the SchemaManager API and is the database the given table is in.
2889
     *
2890
     * Attention: Some platforms only support currentDatabase when they
2891
     * are connected with that database. Cross-database information schema
2892
     * requests may be impossible.
2893
     *
2894
     * @param string $table
2895
     * @param string $currentDatabase
0 ignored issues
show
Documentation introduced by
Should the type for parameter $currentDatabase not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
2896
     *
2897
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2898
     *
2899
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2900
     */
2901
    public function getListTableIndexesSQL($table, $currentDatabase = null)
2902
    {
2903
        throw DBALException::notSupported(__METHOD__);
2904
    }
2905
2906
    /**
2907
     * @param string $table
2908
     *
2909
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2910
     *
2911
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2912
     */
2913
    public function getListTableForeignKeysSQL($table)
2914
    {
2915
        throw DBALException::notSupported(__METHOD__);
2916
    }
2917
2918
    /**
2919
     * @param string $name
2920
     * @param string $sql
2921
     *
2922
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2923
     *
2924
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2925
     */
2926
    public function getCreateViewSQL($name, $sql)
2927
    {
2928
        throw DBALException::notSupported(__METHOD__);
2929
    }
2930
2931
    /**
2932
     * @param string $name
2933
     *
2934
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2935
     *
2936
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2937
     */
2938
    public function getDropViewSQL($name)
2939
    {
2940
        throw DBALException::notSupported(__METHOD__);
2941
    }
2942
2943
    /**
2944
     * Returns the SQL snippet to drop an existing sequence.
2945
     *
2946
     * @param Sequence|string $sequence
2947
     *
2948
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2949
     *
2950
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2951
     */
2952
    public function getDropSequenceSQL($sequence)
2953
    {
2954
        throw DBALException::notSupported(__METHOD__);
2955
    }
2956
2957
    /**
2958
     * @param string $sequenceName
2959
     *
2960
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2961
     *
2962
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2963
     */
2964
    public function getSequenceNextValSQL($sequenceName)
2965
    {
2966
        throw DBALException::notSupported(__METHOD__);
2967
    }
2968
2969
    /**
2970
     * Returns the SQL to create a new database.
2971
     *
2972
     * @param string $database The name of the database that should be created.
2973
     *
2974
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2975
     *
2976
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2977
     */
2978
    public function getCreateDatabaseSQL($database)
2979
    {
2980
        throw DBALException::notSupported(__METHOD__);
2981
    }
2982
2983
    /**
2984
     * Returns the SQL to set the transaction isolation level.
2985
     *
2986
     * @param int $level
2987
     *
2988
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
2989
     *
2990
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2991
     */
2992
    public function getSetTransactionIsolationSQL($level)
2993
    {
2994
        throw DBALException::notSupported(__METHOD__);
2995
    }
2996
2997
    /**
2998
     * Obtains DBMS specific SQL to be used to create datetime fields in
2999
     * statements like CREATE TABLE.
3000
     *
3001
     * @param array $fieldDeclaration
3002
     *
3003
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3004
     *
3005
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3006
     */
3007
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
3008
    {
3009
        throw DBALException::notSupported(__METHOD__);
3010
    }
3011
3012
    /**
3013
     * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields.
3014
     *
3015
     * @param array $fieldDeclaration
3016
     *
3017
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3018
     */
3019
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
3020
    {
3021
        return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
3022
    }
3023
3024
3025
    /**
3026
     * Obtains DBMS specific SQL to be used to create date fields in statements
3027
     * like CREATE TABLE.
3028
     *
3029
     * @param array $fieldDeclaration
3030
     *
3031
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3032
     *
3033
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3034
     */
3035
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
0 ignored issues
show
Unused Code introduced by
The parameter $fieldDeclaration is not used and could be removed.

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

Loading history...
3036
    {
3037
        throw DBALException::notSupported(__METHOD__);
3038
    }
3039
3040
    /**
3041
     * Obtains DBMS specific SQL to be used to create time fields in statements
3042
     * like CREATE TABLE.
3043
     *
3044
     * @param array $fieldDeclaration
3045
     *
3046
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3047
     *
3048
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3049
     */
3050
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
0 ignored issues
show
Unused Code introduced by
The parameter $fieldDeclaration is not used and could be removed.

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

Loading history...
3051
    {
3052
        throw DBALException::notSupported(__METHOD__);
3053
    }
3054
3055
    /**
3056
     * @param array $fieldDeclaration
3057
     *
3058
     * @return string
3059
     */
3060
    public function getFloatDeclarationSQL(array $fieldDeclaration)
3061
    {
3062
        return 'DOUBLE PRECISION';
3063
    }
3064
3065
    /**
3066
     * Gets the default transaction isolation level of the platform.
3067
     *
3068
     * @return int The default isolation level.
3069
     *
3070
     * @see TransactionIsolationLevel
3071
     */
3072
    public function getDefaultTransactionIsolationLevel()
3073
    {
3074
        return TransactionIsolationLevel::READ_COMMITTED;
3075
    }
3076
3077
    /* supports*() methods */
3078
3079
    /**
3080
     * Whether the platform supports sequences.
3081
     *
3082
     * @return bool
3083
     */
3084
    public function supportsSequences()
3085
    {
3086
        return false;
3087
    }
3088
3089
    /**
3090
     * Whether the platform supports identity columns.
3091
     *
3092
     * Identity columns are columns that receive an auto-generated value from the
3093
     * database on insert of a row.
3094
     *
3095
     * @return bool
3096
     */
3097
    public function supportsIdentityColumns()
3098
    {
3099
        return false;
3100
    }
3101
3102
    /**
3103
     * Whether the platform emulates identity columns through sequences.
3104
     *
3105
     * Some platforms that do not support identity columns natively
3106
     * but support sequences can emulate identity columns by using
3107
     * sequences.
3108
     *
3109
     * @return bool
3110
     */
3111
    public function usesSequenceEmulatedIdentityColumns()
3112
    {
3113
        return false;
3114
    }
3115
3116
    /**
3117
     * Returns the name of the sequence for a particular identity column in a particular table.
3118
     *
3119
     * @param string $tableName  The name of the table to return the sequence name for.
3120
     * @param string $columnName The name of the identity column in the table to return the sequence name for.
3121
     *
3122
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3123
     *
3124
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3125
     *
3126
     * @see    usesSequenceEmulatedIdentityColumns
3127
     */
3128
    public function getIdentitySequenceName($tableName, $columnName)
3129
    {
3130
        throw DBALException::notSupported(__METHOD__);
3131
    }
3132
3133
    /**
3134
     * Whether the platform supports indexes.
3135
     *
3136
     * @return bool
3137
     */
3138
    public function supportsIndexes()
3139
    {
3140
        return true;
3141
    }
3142
3143
    /**
3144
     * Whether the platform supports partial indexes.
3145
     *
3146
     * @return bool
3147
     */
3148
    public function supportsPartialIndexes()
3149
    {
3150
        return false;
3151
    }
3152
3153
    /**
3154
     * Whether the platform supports altering tables.
3155
     *
3156
     * @return bool
3157
     */
3158
    public function supportsAlterTable()
3159
    {
3160
        return true;
3161
    }
3162
3163
    /**
3164
     * Whether the platform supports transactions.
3165
     *
3166
     * @return bool
3167
     */
3168
    public function supportsTransactions()
3169
    {
3170
        return true;
3171
    }
3172
3173
    /**
3174
     * Whether the platform supports savepoints.
3175
     *
3176
     * @return bool
3177
     */
3178
    public function supportsSavepoints()
3179
    {
3180
        return true;
3181
    }
3182
3183
    /**
3184
     * Whether the platform supports releasing savepoints.
3185
     *
3186
     * @return bool
3187
     */
3188
    public function supportsReleaseSavepoints()
3189
    {
3190
        return $this->supportsSavepoints();
3191
    }
3192
3193
    /**
3194
     * Whether the platform supports primary key constraints.
3195
     *
3196
     * @return bool
3197
     */
3198
    public function supportsPrimaryConstraints()
3199
    {
3200
        return true;
3201
    }
3202
3203
    /**
3204
     * Whether the platform supports foreign key constraints.
3205
     *
3206
     * @return bool
3207
     */
3208
    public function supportsForeignKeyConstraints()
3209
    {
3210
        return true;
3211
    }
3212
3213
    /**
3214
     * Whether this platform supports onUpdate in foreign key constraints.
3215
     *
3216
     * @return bool
3217
     */
3218
    public function supportsForeignKeyOnUpdate()
3219
    {
3220
        return ($this->supportsForeignKeyConstraints() && true);
3221
    }
3222
3223
    /**
3224
     * Whether the platform supports database schemas.
3225
     *
3226
     * @return bool
3227
     */
3228
    public function supportsSchemas()
3229
    {
3230
        return false;
3231
    }
3232
3233
    /**
3234
     * Whether this platform can emulate schemas.
3235
     *
3236
     * Platforms that either support or emulate schemas don't automatically
3237
     * filter a schema for the namespaced elements in {@link
3238
     * AbstractManager#createSchema}.
3239
     *
3240
     * @return bool
3241
     */
3242
    public function canEmulateSchemas()
3243
    {
3244
        return false;
3245
    }
3246
3247
    /**
3248
     * Returns the default schema name.
3249
     *
3250
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3251
     *
3252
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3253
     */
3254
    public function getDefaultSchemaName()
3255
    {
3256
        throw DBALException::notSupported(__METHOD__);
3257
    }
3258
3259
    /**
3260
     * Whether this platform supports create database.
3261
     *
3262
     * Some databases don't allow to create and drop databases at all or only with certain tools.
3263
     *
3264
     * @return bool
3265
     */
3266
    public function supportsCreateDropDatabase()
3267
    {
3268
        return true;
3269
    }
3270
3271
    /**
3272
     * Whether the platform supports getting the affected rows of a recent update/delete type query.
3273
     *
3274
     * @return bool
3275
     */
3276
    public function supportsGettingAffectedRows()
3277
    {
3278
        return true;
3279
    }
3280
3281
    /**
3282
     * Whether this platform support to add inline column comments as postfix.
3283
     *
3284
     * @return bool
3285
     */
3286
    public function supportsInlineColumnComments()
3287
    {
3288
        return false;
3289
    }
3290
3291
    /**
3292
     * Whether this platform support the proprietary syntax "COMMENT ON asset".
3293
     *
3294
     * @return bool
3295
     */
3296
    public function supportsCommentOnStatement()
3297
    {
3298
        return false;
3299
    }
3300
3301
    /**
3302
     * Does this platform have native guid type.
3303
     *
3304
     * @return bool
3305
     */
3306
    public function hasNativeGuidType()
3307
    {
3308
        return false;
3309
    }
3310
3311
    /**
3312
     * Does this platform have native JSON type.
3313
     *
3314
     * @return bool
3315
     */
3316
    public function hasNativeJsonType()
3317
    {
3318
        return false;
3319
    }
3320
3321
    /**
3322
     * @deprecated
3323
     * @todo Remove in 3.0
3324
     */
3325
    public function getIdentityColumnNullInsertSQL()
3326
    {
3327
        return "";
3328
    }
3329
3330
    /**
3331
     * Whether this platform supports views.
3332
     *
3333
     * @return bool
3334
     */
3335
    public function supportsViews()
3336
    {
3337
        return true;
3338
    }
3339
3340
    /**
3341
     * Does this platform support column collation?
3342
     *
3343
     * @return bool
3344
     */
3345
    public function supportsColumnCollation()
3346
    {
3347
        return false;
3348
    }
3349
3350
    /**
3351
     * Gets the format string, as accepted by the date() function, that describes
3352
     * the format of a stored datetime value of this platform.
3353
     *
3354
     * @return string The format string.
3355
     */
3356
    public function getDateTimeFormatString()
3357
    {
3358
        return 'Y-m-d H:i:s';
3359
    }
3360
3361
    /**
3362
     * Gets the format string, as accepted by the date() function, that describes
3363
     * the format of a stored datetime with timezone value of this platform.
3364
     *
3365
     * @return string The format string.
3366
     */
3367
    public function getDateTimeTzFormatString()
3368
    {
3369
        return 'Y-m-d H:i:s';
3370
    }
3371
3372
    /**
3373
     * Gets the format string, as accepted by the date() function, that describes
3374
     * the format of a stored date value of this platform.
3375
     *
3376
     * @return string The format string.
3377
     */
3378
    public function getDateFormatString()
3379
    {
3380
        return 'Y-m-d';
3381
    }
3382
3383
    /**
3384
     * Gets the format string, as accepted by the date() function, that describes
3385
     * the format of a stored time value of this platform.
3386
     *
3387
     * @return string The format string.
3388
     */
3389
    public function getTimeFormatString()
3390
    {
3391
        return 'H:i:s';
3392
    }
3393
3394
    /**
3395
     * Adds an driver-specific LIMIT clause to the query.
3396
     *
3397
     * @param string   $query
3398
     * @param int|null $limit
3399
     * @param int|null $offset
3400
     *
3401
     * @return string
3402
     *
3403
     * @throws DBALException
3404
     */
3405
    final public function modifyLimitQuery($query, $limit, $offset = null)
3406
    {
3407
        if ($limit !== null) {
3408
            $limit = (int) $limit;
3409
        }
3410
3411
        $offset = (int) $offset;
3412
3413
        if ($offset < 0) {
3414
            throw new DBALException(sprintf(
3415
                'Offset must be a positive integer or zero, %d given',
3416
                $offset
3417
            ));
3418
        }
3419
3420
        if ($offset > 0 && ! $this->supportsLimitOffset()) {
3421
            throw new DBALException(sprintf(
3422
                'Platform %s does not support offset values in limit queries.',
3423
                $this->getName()
3424
            ));
3425
        }
3426
3427
        return $this->doModifyLimitQuery($query, $limit, $offset);
3428
    }
3429
3430
    /**
3431
     * Adds an platform-specific LIMIT clause to the query.
3432
     *
3433
     * @param string   $query
3434
     * @param int|null $limit
3435
     * @param int|null $offset
3436
     *
3437
     * @return string
3438
     */
3439
    protected function doModifyLimitQuery($query, $limit, $offset)
3440
    {
3441
        if ($limit !== null) {
3442
            $query .= ' LIMIT ' . $limit;
3443
        }
3444
3445
        if ($offset > 0) {
3446
            $query .= ' OFFSET ' . $offset;
3447
        }
3448
3449
        return $query;
3450
    }
3451
3452
    /**
3453
     * Whether the database platform support offsets in modify limit clauses.
3454
     *
3455
     * @return bool
3456
     */
3457
    public function supportsLimitOffset()
3458
    {
3459
        return true;
3460
    }
3461
3462
    /**
3463
     * Gets the character casing of a column in an SQL result set of this platform.
3464
     *
3465
     * @param string $column The column name for which to get the correct character casing.
3466
     *
3467
     * @return string The column name in the character casing used in SQL result sets.
3468
     */
3469
    public function getSQLResultCasing($column)
3470
    {
3471
        return $column;
3472
    }
3473
3474
    /**
3475
     * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
3476
     * by restrictions of the platform, like a maximum length.
3477
     *
3478
     * @param string $schemaElementName
3479
     *
3480
     * @return string
3481
     */
3482
    public function fixSchemaElementName($schemaElementName)
3483
    {
3484
        return $schemaElementName;
3485
    }
3486
3487
    /**
3488
     * Maximum length of any given database identifier, like tables or column names.
3489
     *
3490
     * @return int
3491
     */
3492
    public function getMaxIdentifierLength()
3493
    {
3494
        return 63;
3495
    }
3496
3497
    /**
3498
     * Returns the insert SQL for an empty insert statement.
3499
     *
3500
     * @param string $tableName
3501
     * @param string $identifierColumnName
3502
     *
3503
     * @return string
3504
     */
3505
    public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
3506
    {
3507
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
3508
    }
3509
3510
    /**
3511
     * Generates a Truncate Table SQL statement for a given table.
3512
     *
3513
     * Cascade is not supported on many platforms but would optionally cascade the truncate by
3514
     * following the foreign keys.
3515
     *
3516
     * @param string $tableName
3517
     * @param bool   $cascade
3518
     *
3519
     * @return string
3520
     */
3521
    public function getTruncateTableSQL($tableName, $cascade = false)
3522
    {
3523
        $tableIdentifier = new Identifier($tableName);
3524
3525
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3526
    }
3527
3528
    /**
3529
     * This is for test reasons, many vendors have special requirements for dummy statements.
3530
     *
3531
     * @return string
3532
     */
3533
    public function getDummySelectSQL()
3534
    {
3535
        $expression = func_num_args() > 0 ? func_get_arg(0) : '1';
3536
3537
        return sprintf('SELECT %s', $expression);
3538
    }
3539
3540
    /**
3541
     * Returns the SQL to create a new savepoint.
3542
     *
3543
     * @param string $savepoint
3544
     *
3545
     * @return string
3546
     */
3547
    public function createSavePoint($savepoint)
3548
    {
3549
        return 'SAVEPOINT ' . $savepoint;
3550
    }
3551
3552
    /**
3553
     * Returns the SQL to release a savepoint.
3554
     *
3555
     * @param string $savepoint
3556
     *
3557
     * @return string
3558
     */
3559
    public function releaseSavePoint($savepoint)
3560
    {
3561
        return 'RELEASE SAVEPOINT ' . $savepoint;
3562
    }
3563
3564
    /**
3565
     * Returns the SQL to rollback a savepoint.
3566
     *
3567
     * @param string $savepoint
3568
     *
3569
     * @return string
3570
     */
3571
    public function rollbackSavePoint($savepoint)
3572
    {
3573
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3574
    }
3575
3576
    /**
3577
     * Returns the keyword list instance of this platform.
3578
     *
3579
     * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList
3580
     *
3581
     * @throws \Doctrine\DBAL\DBALException If no keyword list is specified.
3582
     */
3583
    final public function getReservedKeywordsList()
3584
    {
3585
        // Check for an existing instantiation of the keywords class.
3586
        if ($this->_keywords) {
3587
            return $this->_keywords;
3588
        }
3589
3590
        $class = $this->getReservedKeywordsClass();
3591
        $keywords = new $class;
3592
        if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) {
3593
            throw DBALException::notSupported(__METHOD__);
3594
        }
3595
3596
        // Store the instance so it doesn't need to be generated on every request.
3597
        $this->_keywords = $keywords;
3598
3599
        return $keywords;
3600
    }
3601
3602
    /**
3603
     * Returns the class name of the reserved keywords list.
3604
     *
3605
     * @return string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use NoType.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
3606
     *
3607
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3608
     */
3609
    protected function getReservedKeywordsClass()
3610
    {
3611
        throw DBALException::notSupported(__METHOD__);
3612
    }
3613
3614
    /**
3615
     * Quotes a literal string.
3616
     * This method is NOT meant to fix SQL injections!
3617
     * It is only meant to escape this platform's string literal
3618
     * quote character inside the given literal string.
3619
     *
3620
     * @param string $str The literal string to be quoted.
3621
     *
3622
     * @return string The quoted literal string.
3623
     */
3624
    public function quoteStringLiteral($str)
3625
    {
3626
        $c = $this->getStringLiteralQuoteCharacter();
3627
3628
        return $c . str_replace($c, $c . $c, $str) . $c;
3629
    }
3630
3631
    /**
3632
     * Gets the character used for string literal quoting.
3633
     *
3634
     * @return string
3635
     */
3636
    public function getStringLiteralQuoteCharacter()
3637
    {
3638
        return "'";
3639
    }
3640
3641
    /**
3642
     * Escapes metacharacters in a string intended to be used with a LIKE
3643
     * operator.
3644
     *
3645
     * @param string $inputString a literal, unquoted string
3646
     * @param string $escapeChar  should be reused by the caller in the LIKE
3647
     *                            expression.
3648
     */
3649
    final public function escapeStringForLike(string $inputString, string $escapeChar) : string
3650
    {
3651
        return preg_replace(
3652
            '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u',
3653
            addcslashes($escapeChar, '\\') . '$1',
3654
            $inputString
3655
        );
3656
    }
3657
3658
    protected function getLikeWildcardCharacters() : string
3659
    {
3660
        return '%_';
3661
    }
3662
}
3663