Failed Conditions
Pull Request — master (#2762)
by Evgenij
04:45
created

AbstractPlatform::getInsertMaxRows()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Platforms;
21
22
use Doctrine\DBAL\DBALException;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\Schema\Identifier;
25
use Doctrine\DBAL\Types;
26
use Doctrine\DBAL\Schema\Constraint;
27
use Doctrine\DBAL\Schema\Sequence;
28
use Doctrine\DBAL\Schema\Table;
29
use Doctrine\DBAL\Schema\Index;
30
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
31
use Doctrine\DBAL\Schema\TableDiff;
32
use Doctrine\DBAL\Schema\Column;
33
use Doctrine\DBAL\Schema\ColumnDiff;
34
use Doctrine\DBAL\Types\Type;
35
use Doctrine\DBAL\Events;
36
use Doctrine\Common\EventManager;
37
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
38
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
39
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
40
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
41
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
42
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
43
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
44
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
45
46
/**
47
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
48
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
49
 * They are a passive source of information.
50
 *
51
 * @link   www.doctrine-project.org
52
 * @since  2.0
53
 * @author Guilherme Blanco <[email protected]>
54
 * @author Jonathan Wage <[email protected]>
55
 * @author Roman Borschel <[email protected]>
56
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
57
 * @author Benjamin Eberlei <[email protected]>
58
 * @todo   Remove any unnecessary methods.
59
 */
60
abstract class AbstractPlatform
61
{
62
    /**
63
     * @var integer
64
     */
65
    const CREATE_INDEXES = 1;
66
67
    /**
68
     * @var integer
69
     */
70
    const CREATE_FOREIGNKEYS = 2;
71
72
    /**
73
     * @var string
74
     */
75
    const DATE_INTERVAL_UNIT_SECOND = 'SECOND';
76
77
    /**
78
     * @var string
79
     */
80
    const DATE_INTERVAL_UNIT_MINUTE = 'MINUTE';
81
82
    /**
83
     * @var string
84
     */
85
    const DATE_INTERVAL_UNIT_HOUR = 'HOUR';
86
87
    /**
88
     * @var string
89
     */
90
    const DATE_INTERVAL_UNIT_DAY = 'DAY';
91
92
    /**
93
     * @var string
94
     */
95
    const DATE_INTERVAL_UNIT_WEEK = 'WEEK';
96
97
    /**
98
     * @var string
99
     */
100
    const DATE_INTERVAL_UNIT_MONTH = 'MONTH';
101
102
    /**
103
     * @var string
104
     */
105
    const DATE_INTERVAL_UNIT_QUARTER = 'QUARTER';
106
107
    /**
108
     * @var string
109
     */
110
    const DATE_INTERVAL_UNIT_YEAR = 'YEAR';
111
112
    /**
113
     * @var integer
114
     */
115
    const TRIM_UNSPECIFIED = 0;
116
117
    /**
118
     * @var integer
119
     */
120
    const TRIM_LEADING = 1;
121
122
    /**
123
     * @var integer
124
     */
125
    const TRIM_TRAILING = 2;
126
127
    /**
128
     * @var integer
129
     */
130
    const TRIM_BOTH = 3;
131
132
    /**
133
     * @var array|null
134
     */
135
    protected $doctrineTypeMapping = null;
136
137
    /**
138
     * Contains a list of all columns that should generate parseable column comments for type-detection
139
     * in reverse engineering scenarios.
140
     *
141
     * @var array|null
142
     */
143
    protected $doctrineTypeComments = null;
144
145
    /**
146
     * @var \Doctrine\Common\EventManager
147
     */
148
    protected $_eventManager;
149
150
    /**
151
     * Holds the KeywordList instance for the current platform.
152
     *
153
     * @var \Doctrine\DBAL\Platforms\Keywords\KeywordList
154
     */
155
    protected $_keywords;
156
157
    /**
158
     * Constructor.
159
     */
160 3005
    public function __construct()
161
    {
162 3005
    }
163
164
    /**
165
     * Sets the EventManager used by the Platform.
166
     *
167
     * @param \Doctrine\Common\EventManager $eventManager
168
     */
169 80
    public function setEventManager(EventManager $eventManager)
170
    {
171 80
        $this->_eventManager = $eventManager;
172 80
    }
173
174
    /**
175
     * Gets the EventManager used by the Platform.
176
     *
177
     * @return \Doctrine\Common\EventManager
178
     */
179 43
    public function getEventManager()
180
    {
181 43
        return $this->_eventManager;
182
    }
183
184
    /**
185
     * Returns the SQL snippet that declares a boolean column.
186
     *
187
     * @param array $columnDef
188
     *
189
     * @return string
190
     */
191
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
192
193
    /**
194
     * Returns the SQL snippet that declares a 4 byte integer column.
195
     *
196
     * @param array $columnDef
197
     *
198
     * @return string
199
     */
200
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
201
202
    /**
203
     * Returns the SQL snippet that declares an 8 byte integer column.
204
     *
205
     * @param array $columnDef
206
     *
207
     * @return string
208
     */
209
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
210
211
    /**
212
     * Returns the SQL snippet that declares a 2 byte integer column.
213
     *
214
     * @param array $columnDef
215
     *
216
     * @return string
217
     */
218
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
219
220
    /**
221
     * Returns the SQL snippet that declares common properties of an integer column.
222
     *
223
     * @param array $columnDef
224
     *
225
     * @return string
226
     */
227
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
228
229
    /**
230
     * Lazy load Doctrine Type Mappings.
231
     *
232
     * @return void
233
     */
234
    abstract protected function initializeDoctrineTypeMappings();
235
236
    /**
237
     * Initializes Doctrine Type Mappings with the platform defaults
238
     * and with all additional type mappings.
239
     *
240
     * @return void
241
     */
242 87
    private function initializeAllDoctrineTypeMappings()
243
    {
244 87
        $this->initializeDoctrineTypeMappings();
245
246 87
        foreach (Type::getTypesMap() as $typeName => $className) {
247 87
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
248 87
                $this->doctrineTypeMapping[$dbType] = $typeName;
249
            }
250
        }
251 87
    }
252
253
    /**
254
     * Returns the SQL snippet used to declare a VARCHAR column type.
255
     *
256
     * @param array $field
257
     *
258
     * @return string
259
     */
260 304
    public function getVarcharTypeDeclarationSQL(array $field)
261
    {
262 304
        if ( !isset($field['length'])) {
263 73
            $field['length'] = $this->getVarcharDefaultLength();
264
        }
265
266 304
        $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
267
268 304
        if ($field['length'] > $this->getVarcharMaxLength()) {
269
            return $this->getClobTypeDeclarationSQL($field);
270
        }
271
272 304
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
273
    }
274
275
    /**
276
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
277
     *
278
     * @param array $field The column definition.
279
     *
280
     * @return string
281
     */
282 20
    public function getBinaryTypeDeclarationSQL(array $field)
283
    {
284 20
        if ( ! isset($field['length'])) {
285 17
            $field['length'] = $this->getBinaryDefaultLength();
286
        }
287
288 20
        $fixed = isset($field['fixed']) ? $field['fixed'] : false;
289
290 20
        if ($field['length'] > $this->getBinaryMaxLength()) {
291 19
            return $this->getBlobTypeDeclarationSQL($field);
292
        }
293
294 17
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
295
    }
296
297
    /**
298
     * Returns the SQL snippet to declare a GUID/UUID field.
299
     *
300
     * By default this maps directly to a CHAR(36) and only maps to more
301
     * special datatypes when the underlying databases support this datatype.
302
     *
303
     * @param array $field
304
     *
305
     * @return string
306
     */
307 5
    public function getGuidTypeDeclarationSQL(array $field)
308
    {
309 5
        $field['length'] = 36;
310 5
        $field['fixed']  = true;
311
312 5
        return $this->getVarcharTypeDeclarationSQL($field);
313
    }
314
315
    /**
316
     * Returns the SQL snippet to declare a JSON field.
317
     *
318
     * By default this maps directly to a CLOB and only maps to more
319
     * special datatypes when the underlying databases support this datatype.
320
     *
321
     * @param array $field
322
     *
323
     * @return string
324
     */
325 28
    public function getJsonTypeDeclarationSQL(array $field)
326
    {
327 28
        return $this->getClobTypeDeclarationSQL($field);
328
    }
329
330
    /**
331
     * @param integer $length
332
     * @param boolean $fixed
333
     *
334
     * @return string
335
     *
336
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
337
     */
338
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
339
    {
340
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
341
    }
342
343
    /**
344
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
345
     *
346
     * @param integer $length The length of the column.
347
     * @param boolean $fixed  Whether the column length is fixed.
348
     *
349
     * @return string
350
     *
351
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
352
     */
353
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
354
    {
355
        throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.');
356
    }
357
358
    /**
359
     * Returns the SQL snippet used to declare a CLOB column type.
360
     *
361
     * @param array $field
362
     *
363
     * @return string
364
     */
365
    abstract public function getClobTypeDeclarationSQL(array $field);
366
367
    /**
368
     * Returns the SQL Snippet used to declare a BLOB column type.
369
     *
370
     * @param array $field
371
     *
372
     * @return string
373
     */
374
    abstract public function getBlobTypeDeclarationSQL(array $field);
375
376
    /**
377
     * Gets the name of the platform.
378
     *
379
     * @return string
380
     */
381
    abstract public function getName();
382
383
    /**
384
     * Registers a doctrine type to be used in conjunction with a column type of this platform.
385
     *
386
     * @param string $dbType
387
     * @param string $doctrineType
388
     *
389
     * @throws \Doctrine\DBAL\DBALException If the type is not found.
390
     */
391 49
    public function registerDoctrineTypeMapping($dbType, $doctrineType)
392
    {
393 49
        if ($this->doctrineTypeMapping === null) {
394 49
            $this->initializeAllDoctrineTypeMappings();
395
        }
396
397 49
        if (!Types\Type::hasType($doctrineType)) {
398 16
            throw DBALException::typeNotFound($doctrineType);
399
        }
400
401 33
        $dbType = strtolower($dbType);
402 33
        $this->doctrineTypeMapping[$dbType] = $doctrineType;
403
404 33
        $doctrineType = Type::getType($doctrineType);
405
406 33
        if ($doctrineType->requiresSQLCommentHint($this)) {
407 16
            $this->markDoctrineTypeCommented($doctrineType);
408
        }
409 33
    }
410
411
    /**
412
     * Gets the Doctrine type that is mapped for the given database column type.
413
     *
414
     * @param string $dbType
415
     *
416
     * @return string
417
     *
418
     * @throws \Doctrine\DBAL\DBALException
419
     */
420 91
    public function getDoctrineTypeMapping($dbType)
421
    {
422 91
        if ($this->doctrineTypeMapping === null) {
423 19
            $this->initializeAllDoctrineTypeMappings();
424
        }
425
426 91
        $dbType = strtolower($dbType);
427
428 91
        if (!isset($this->doctrineTypeMapping[$dbType])) {
429 16
            throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it.");
430
        }
431
432 75
        return $this->doctrineTypeMapping[$dbType];
433
    }
434
435
    /**
436
     * Checks if a database type is currently supported by this platform.
437
     *
438
     * @param string $dbType
439
     *
440
     * @return boolean
441
     */
442 20
    public function hasDoctrineTypeMappingFor($dbType)
443
    {
444 20
        if ($this->doctrineTypeMapping === null) {
445 19
            $this->initializeAllDoctrineTypeMappings();
446
        }
447
448 20
        $dbType = strtolower($dbType);
449
450 20
        return isset($this->doctrineTypeMapping[$dbType]);
451
    }
452
453
    /**
454
     * Initializes the Doctrine Type comments instance variable for in_array() checks.
455
     *
456
     * @return void
457
     */
458 748
    protected function initializeCommentedDoctrineTypes()
459
    {
460 748
        $this->doctrineTypeComments = array();
461
462 748
        foreach (Type::getTypesMap() as $typeName => $className) {
463 748
            $type = Type::getType($typeName);
464
465 748
            if ($type->requiresSQLCommentHint($this)) {
466 748
                $this->doctrineTypeComments[] = $typeName;
467
            }
468
        }
469 748
    }
470
471
    /**
472
     * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type?
473
     *
474
     * @param \Doctrine\DBAL\Types\Type $doctrineType
475
     *
476
     * @return boolean
477
     */
478 860
    public function isCommentedDoctrineType(Type $doctrineType)
479
    {
480 860
        if ($this->doctrineTypeComments === null) {
481 732
            $this->initializeCommentedDoctrineTypes();
482
        }
483
484 860
        return in_array($doctrineType->getName(), $this->doctrineTypeComments);
485
    }
486
487
    /**
488
     * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements.
489
     *
490
     * @param string|\Doctrine\DBAL\Types\Type $doctrineType
491
     *
492
     * @return void
493
     */
494 16
    public function markDoctrineTypeCommented($doctrineType)
495
    {
496 16
        if ($this->doctrineTypeComments === null) {
497 16
            $this->initializeCommentedDoctrineTypes();
498
        }
499
500 16
        $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
501 16
    }
502
503
    /**
504
     * Gets the comment to append to a column comment that helps parsing this type in reverse engineering.
505
     *
506
     * @param \Doctrine\DBAL\Types\Type $doctrineType
507
     *
508
     * @return string
509
     */
510 38
    public function getDoctrineTypeComment(Type $doctrineType)
511
    {
512 38
        return '(DC2Type:' . $doctrineType->getName() . ')';
513
    }
514
515
    /**
516
     * Gets the comment of a passed column modified by potential doctrine type comment hints.
517
     *
518
     * @param \Doctrine\DBAL\Schema\Column $column
519
     *
520
     * @return string
521
     */
522 445
    protected function getColumnComment(Column $column)
523
    {
524 445
        $comment = $column->getComment();
525
526 445
        if ($this->isCommentedDoctrineType($column->getType())) {
527 38
            $comment .= $this->getDoctrineTypeComment($column->getType());
528
        }
529
530 445
        return $comment;
531
    }
532
533
    /**
534
     * Gets the character used for identifier quoting.
535
     *
536
     * @return string
537
     */
538 274
    public function getIdentifierQuoteCharacter()
539
    {
540 274
        return '"';
541
    }
542
543
    /**
544
     * Gets the string portion that starts an SQL comment.
545
     *
546
     * @return string
547
     */
548
    public function getSqlCommentStartString()
549
    {
550
        return "--";
551
    }
552
553
    /**
554
     * Gets the string portion that ends an SQL comment.
555
     *
556
     * @return string
557
     */
558
    public function getSqlCommentEndString()
559
    {
560
        return "\n";
561
    }
562
563
    /**
564
     * Gets the maximum length of a varchar field.
565
     *
566
     * @return integer
567
     */
568 178
    public function getVarcharMaxLength()
569
    {
570 178
        return 4000;
571
    }
572
573
    /**
574
     * Gets the default length of a varchar field.
575
     *
576
     * @return integer
577
     */
578 61
    public function getVarcharDefaultLength()
579
    {
580 61
        return 255;
581
    }
582
583
    /**
584
     * Gets the maximum length of a binary field.
585
     *
586
     * @return integer
587
     */
588
    public function getBinaryMaxLength()
589
    {
590
        return 4000;
591
    }
592
593
    /**
594
     * Gets the default length of a binary field.
595
     *
596
     * @return integer
597
     */
598 12
    public function getBinaryDefaultLength()
599
    {
600 12
        return 255;
601
    }
602
603
    /**
604
     * Returns the maximum number of rows that can be inserted in a single INSERT statement.
605
     *
606
     * @return integer
607
     */
608
    public function getInsertMaxRows()
609
    {
610
        return 0;
611
    }
612
613
    /**
614
     * Gets all SQL wildcard characters of the platform.
615
     *
616
     * @return array
617
     */
618
    public function getWildcards()
619
    {
620
        return array('%', '_');
621
    }
622
623
    /**
624
     * Returns the regular expression operator.
625
     *
626
     * @return string
627
     *
628
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
629
     */
630 5
    public function getRegexpExpression()
631
    {
632 5
        throw DBALException::notSupported(__METHOD__);
633
    }
634
635
    /**
636
     * Returns the global unique identifier expression.
637
     *
638
     * @return string
639
     *
640
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
641
     */
642
    public function getGuidExpression()
643
    {
644
        throw DBALException::notSupported(__METHOD__);
645
    }
646
647
    /**
648
     * Returns the SQL snippet to get the average value of a column.
649
     *
650
     * @param string $column The column to use.
651
     *
652
     * @return string Generated SQL including an AVG aggregate function.
653
     */
654
    public function getAvgExpression($column)
655
    {
656
        return 'AVG(' . $column . ')';
657
    }
658
659
    /**
660
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
661
     *
662
     * If a '*' is used instead of a column the number of selected rows is returned.
663
     *
664
     * @param string|integer $column The column to use.
665
     *
666
     * @return string Generated SQL including a COUNT aggregate function.
667
     */
668
    public function getCountExpression($column)
669
    {
670
        return 'COUNT(' . $column . ')';
671
    }
672
673
    /**
674
     * Returns the SQL snippet to get the highest value of a column.
675
     *
676
     * @param string $column The column to use.
677
     *
678
     * @return string Generated SQL including a MAX aggregate function.
679
     */
680
    public function getMaxExpression($column)
681
    {
682
        return 'MAX(' . $column . ')';
683
    }
684
685
    /**
686
     * Returns the SQL snippet to get the lowest value of a column.
687
     *
688
     * @param string $column The column to use.
689
     *
690
     * @return string Generated SQL including a MIN aggregate function.
691
     */
692
    public function getMinExpression($column)
693
    {
694
        return 'MIN(' . $column . ')';
695
    }
696
697
    /**
698
     * Returns the SQL snippet to get the total sum of a column.
699
     *
700
     * @param string $column The column to use.
701
     *
702
     * @return string Generated SQL including a SUM aggregate function.
703
     */
704
    public function getSumExpression($column)
705
    {
706
        return 'SUM(' . $column . ')';
707
    }
708
709
    // scalar functions
710
711
    /**
712
     * Returns the SQL snippet to get the md5 sum of a field.
713
     *
714
     * Note: Not SQL92, but common functionality.
715
     *
716
     * @param string $column
717
     *
718
     * @return string
719
     */
720
    public function getMd5Expression($column)
721
    {
722
        return 'MD5(' . $column . ')';
723
    }
724
725
    /**
726
     * Returns the SQL snippet to get the length of a text field.
727
     *
728
     * @param string $column
729
     *
730
     * @return string
731
     */
732
    public function getLengthExpression($column)
733
    {
734
        return 'LENGTH(' . $column . ')';
735
    }
736
737
    /**
738
     * Returns the SQL snippet to get the squared value of a column.
739
     *
740
     * @param string $column The column to use.
741
     *
742
     * @return string Generated SQL including an SQRT aggregate function.
743
     */
744
    public function getSqrtExpression($column)
745
    {
746
        return 'SQRT(' . $column . ')';
747
    }
748
749
    /**
750
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
751
     *
752
     * @param string  $column
753
     * @param integer $decimals
754
     *
755
     * @return string
756
     */
757
    public function getRoundExpression($column, $decimals = 0)
758
    {
759
        return 'ROUND(' . $column . ', ' . $decimals . ')';
760
    }
761
762
    /**
763
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
764
     *
765
     * @param string $expression1
766
     * @param string $expression2
767
     *
768
     * @return string
769
     */
770
    public function getModExpression($expression1, $expression2)
771
    {
772
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
773
    }
774
775
    /**
776
     * Returns the SQL snippet to trim a string.
777
     *
778
     * @param string         $str  The expression to apply the trim to.
779
     * @param integer        $pos  The position of the trim (leading/trailing/both).
780
     * @param string|boolean $char The char to trim, has to be quoted already. Defaults to space.
781
     *
782
     * @return string
783
     */
784
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
785
    {
786
        $expression = '';
787
788
        switch ($pos) {
789
            case self::TRIM_LEADING:
790
                $expression = 'LEADING ';
791
                break;
792
793
            case self::TRIM_TRAILING:
794
                $expression = 'TRAILING ';
795
                break;
796
797
            case self::TRIM_BOTH:
798
                $expression = 'BOTH ';
799
                break;
800
        }
801
802
        if (false !== $char) {
803
            $expression .= $char . ' ';
804
        }
805
806
        if ($pos || false !== $char) {
807
            $expression .= 'FROM ';
808
        }
809
810
        return 'TRIM(' . $expression . $str . ')';
811
    }
812
813
    /**
814
     * Returns the SQL snippet to trim trailing space characters from the expression.
815
     *
816
     * @param string $str Literal string or column name.
817
     *
818
     * @return string
819
     */
820 4
    public function getRtrimExpression($str)
821
    {
822 4
        return 'RTRIM(' . $str . ')';
823
    }
824
825
    /**
826
     * Returns the SQL snippet to trim leading space characters from the expression.
827
     *
828
     * @param string $str Literal string or column name.
829
     *
830
     * @return string
831
     */
832 4
    public function getLtrimExpression($str)
833
    {
834 4
        return 'LTRIM(' . $str . ')';
835
    }
836
837
    /**
838
     * Returns the SQL snippet to change all characters from the expression to uppercase,
839
     * according to the current character set mapping.
840
     *
841
     * @param string $str Literal string or column name.
842
     *
843
     * @return string
844
     */
845
    public function getUpperExpression($str)
846
    {
847
        return 'UPPER(' . $str . ')';
848
    }
849
850
    /**
851
     * Returns the SQL snippet to change all characters from the expression to lowercase,
852
     * according to the current character set mapping.
853
     *
854
     * @param string $str Literal string or column name.
855
     *
856
     * @return string
857
     */
858
    public function getLowerExpression($str)
859
    {
860
        return 'LOWER(' . $str . ')';
861
    }
862
863
    /**
864
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
865
     *
866
     * @param string          $str      Literal string.
867
     * @param string          $substr   Literal string to find.
868
     * @param integer|boolean $startPos Position to start at, beginning of string by default.
869
     *
870
     * @return string
871
     *
872
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
873
     */
874
    public function getLocateExpression($str, $substr, $startPos = false)
875
    {
876
        throw DBALException::notSupported(__METHOD__);
877
    }
878
879
    /**
880
     * Returns the SQL snippet to get the current system date.
881
     *
882
     * @return string
883
     */
884
    public function getNowExpression()
885
    {
886
        return 'NOW()';
887
    }
888
889
    /**
890
     * Returns a SQL snippet to get a substring inside an SQL statement.
891
     *
892
     * Note: Not SQL92, but common functionality.
893
     *
894
     * SQLite only supports the 2 parameter variant of this function.
895
     *
896
     * @param string       $value  An sql string literal or column name/alias.
897
     * @param integer      $from   Where to start the substring portion.
898
     * @param integer|null $length The substring portion length.
899
     *
900
     * @return string
901
     */
902 View Code Duplication
    public function getSubstringExpression($value, $from, $length = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
903
    {
904
        if ($length === null) {
905
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
906
        }
907
908
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
909
    }
910
911
    /**
912
     * Returns a SQL snippet to concatenate the given expressions.
913
     *
914
     * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
915
     *
916
     * @return string
917
     */
918 5
    public function getConcatExpression()
919
    {
920 5
        return join(' || ', func_get_args());
921
    }
922
923
    /**
924
     * Returns the SQL for a logical not.
925
     *
926
     * Example:
927
     * <code>
928
     * $q = new Doctrine_Query();
929
     * $e = $q->expr;
930
     * $q->select('*')->from('table')
931
     *   ->where($e->eq('id', $e->not('null'));
932
     * </code>
933
     *
934
     * @param string $expression
935
     *
936
     * @return string The logical expression.
937
     */
938
    public function getNotExpression($expression)
939
    {
940
        return 'NOT(' . $expression . ')';
941
    }
942
943
    /**
944
     * Returns the SQL that checks if an expression is null.
945
     *
946
     * @param string $expression The expression that should be compared to null.
947
     *
948
     * @return string The logical expression.
949
     */
950 4
    public function getIsNullExpression($expression)
951
    {
952 4
        return $expression . ' IS NULL';
953
    }
954
955
    /**
956
     * Returns the SQL that checks if an expression is not null.
957
     *
958
     * @param string $expression The expression that should be compared to null.
959
     *
960
     * @return string The logical expression.
961
     */
962
    public function getIsNotNullExpression($expression)
963
    {
964
        return $expression . ' IS NOT NULL';
965
    }
966
967
    /**
968
     * Returns the SQL that checks if an expression evaluates to a value between two values.
969
     *
970
     * The parameter $expression is checked if it is between $value1 and $value2.
971
     *
972
     * Note: There is a slight difference in the way BETWEEN works on some databases.
973
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
974
     * independence you should avoid using between().
975
     *
976
     * @param string $expression The value to compare to.
977
     * @param string $value1     The lower value to compare with.
978
     * @param string $value2     The higher value to compare with.
979
     *
980
     * @return string The logical expression.
981
     */
982
    public function getBetweenExpression($expression, $value1, $value2)
983
    {
984
        return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
985
    }
986
987
    /**
988
     * Returns the SQL to get the arccosine of a value.
989
     *
990
     * @param string $value
991
     *
992
     * @return string
993
     */
994
    public function getAcosExpression($value)
995
    {
996
        return 'ACOS(' . $value . ')';
997
    }
998
999
    /**
1000
     * Returns the SQL to get the sine of a value.
1001
     *
1002
     * @param string $value
1003
     *
1004
     * @return string
1005
     */
1006
    public function getSinExpression($value)
1007
    {
1008
        return 'SIN(' . $value . ')';
1009
    }
1010
1011
    /**
1012
     * Returns the SQL to get the PI value.
1013
     *
1014
     * @return string
1015
     */
1016
    public function getPiExpression()
1017
    {
1018
        return 'PI()';
1019
    }
1020
1021
    /**
1022
     * Returns the SQL to get the cosine of a value.
1023
     *
1024
     * @param string $value
1025
     *
1026
     * @return string
1027
     */
1028
    public function getCosExpression($value)
1029
    {
1030
        return 'COS(' . $value . ')';
1031
    }
1032
1033
    /**
1034
     * Returns the SQL to calculate the difference in days between the two passed dates.
1035
     *
1036
     * Computes diff = date1 - date2.
1037
     *
1038
     * @param string $date1
1039
     * @param string $date2
1040
     *
1041
     * @return string
1042
     *
1043
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1044
     */
1045
    public function getDateDiffExpression($date1, $date2)
1046
    {
1047
        throw DBALException::notSupported(__METHOD__);
1048
    }
1049
1050
    /**
1051
     * Returns the SQL to add the number of given seconds to a date.
1052
     *
1053
     * @param string  $date
1054
     * @param integer $seconds
1055
     *
1056
     * @return string
1057
     *
1058
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1059
     */
1060 6
    public function getDateAddSecondsExpression($date, $seconds)
1061
    {
1062 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1063
    }
1064
1065
    /**
1066
     * Returns the SQL to subtract the number of given seconds from a date.
1067
     *
1068
     * @param string  $date
1069
     * @param integer $seconds
1070
     *
1071
     * @return string
1072
     *
1073
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1074
     */
1075 6
    public function getDateSubSecondsExpression($date, $seconds)
1076
    {
1077 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1078
    }
1079
1080
    /**
1081
     * Returns the SQL to add the number of given minutes to a date.
1082
     *
1083
     * @param string  $date
1084
     * @param integer $minutes
1085
     *
1086
     * @return string
1087
     *
1088
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1089
     */
1090 6
    public function getDateAddMinutesExpression($date, $minutes)
1091
    {
1092 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1093
    }
1094
1095
    /**
1096
     * Returns the SQL to subtract the number of given minutes from a date.
1097
     *
1098
     * @param string  $date
1099
     * @param integer $minutes
1100
     *
1101
     * @return string
1102
     *
1103
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1104
     */
1105 6
    public function getDateSubMinutesExpression($date, $minutes)
1106
    {
1107 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1108
    }
1109
1110
    /**
1111
     * Returns the SQL to add the number of given hours to a date.
1112
     *
1113
     * @param string  $date
1114
     * @param integer $hours
1115
     *
1116
     * @return string
1117
     *
1118
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1119
     */
1120 6
    public function getDateAddHourExpression($date, $hours)
1121
    {
1122 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1123
    }
1124
1125
    /**
1126
     * Returns the SQL to subtract the number of given hours to a date.
1127
     *
1128
     * @param string  $date
1129
     * @param integer $hours
1130
     *
1131
     * @return string
1132
     *
1133
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1134
     */
1135 6
    public function getDateSubHourExpression($date, $hours)
1136
    {
1137 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1138
    }
1139
1140
    /**
1141
     * Returns the SQL to add the number of given days to a date.
1142
     *
1143
     * @param string  $date
1144
     * @param integer $days
1145
     *
1146
     * @return string
1147
     *
1148
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1149
     */
1150 6
    public function getDateAddDaysExpression($date, $days)
1151
    {
1152 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, self::DATE_INTERVAL_UNIT_DAY);
1153
    }
1154
1155
    /**
1156
     * Returns the SQL to subtract the number of given days to a date.
1157
     *
1158
     * @param string  $date
1159
     * @param integer $days
1160
     *
1161
     * @return string
1162
     *
1163
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1164
     */
1165 6
    public function getDateSubDaysExpression($date, $days)
1166
    {
1167 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, self::DATE_INTERVAL_UNIT_DAY);
1168
    }
1169
1170
    /**
1171
     * Returns the SQL to add the number of given weeks to a date.
1172
     *
1173
     * @param string  $date
1174
     * @param integer $weeks
1175
     *
1176
     * @return string
1177
     *
1178
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1179
     */
1180 6
    public function getDateAddWeeksExpression($date, $weeks)
1181
    {
1182 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1183
    }
1184
1185
    /**
1186
     * Returns the SQL to subtract the number of given weeks from a date.
1187
     *
1188
     * @param string  $date
1189
     * @param integer $weeks
1190
     *
1191
     * @return string
1192
     *
1193
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1194
     */
1195 6
    public function getDateSubWeeksExpression($date, $weeks)
1196
    {
1197 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1198
    }
1199
1200
    /**
1201
     * Returns the SQL to add the number of given months to a date.
1202
     *
1203
     * @param string  $date
1204
     * @param integer $months
1205
     *
1206
     * @return string
1207
     *
1208
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1209
     */
1210 6
    public function getDateAddMonthExpression($date, $months)
1211
    {
1212 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, self::DATE_INTERVAL_UNIT_MONTH);
1213
    }
1214
1215
    /**
1216
     * Returns the SQL to subtract the number of given months to a date.
1217
     *
1218
     * @param string  $date
1219
     * @param integer $months
1220
     *
1221
     * @return string
1222
     *
1223
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1224
     */
1225 6
    public function getDateSubMonthExpression($date, $months)
1226
    {
1227 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, self::DATE_INTERVAL_UNIT_MONTH);
1228
    }
1229
1230
    /**
1231
     * Returns the SQL to add the number of given quarters to a date.
1232
     *
1233
     * @param string  $date
1234
     * @param integer $quarters
1235
     *
1236
     * @return string
1237
     *
1238
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1239
     */
1240 6
    public function getDateAddQuartersExpression($date, $quarters)
1241
    {
1242 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1243
    }
1244
1245
    /**
1246
     * Returns the SQL to subtract the number of given quarters from a date.
1247
     *
1248
     * @param string  $date
1249
     * @param integer $quarters
1250
     *
1251
     * @return string
1252
     *
1253
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1254
     */
1255 6
    public function getDateSubQuartersExpression($date, $quarters)
1256
    {
1257 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1258
    }
1259
1260
    /**
1261
     * Returns the SQL to add the number of given years to a date.
1262
     *
1263
     * @param string  $date
1264
     * @param integer $years
1265
     *
1266
     * @return string
1267
     *
1268
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1269
     */
1270 6
    public function getDateAddYearsExpression($date, $years)
1271
    {
1272 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, self::DATE_INTERVAL_UNIT_YEAR);
1273
    }
1274
1275
    /**
1276
     * Returns the SQL to subtract the number of given years from a date.
1277
     *
1278
     * @param string  $date
1279
     * @param integer $years
1280
     *
1281
     * @return string
1282
     *
1283
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1284
     */
1285 6
    public function getDateSubYearsExpression($date, $years)
1286
    {
1287 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, self::DATE_INTERVAL_UNIT_YEAR);
1288
    }
1289
1290
    /**
1291
     * Returns the SQL for a date arithmetic expression.
1292
     *
1293
     * @param string  $date     The column or literal representing a date to perform the arithmetic operation on.
1294
     * @param string  $operator The arithmetic operator (+ or -).
1295
     * @param integer $interval The interval that shall be calculated into the date.
1296
     * @param string  $unit     The unit of the interval that shall be calculated into the date.
1297
     *                          One of the DATE_INTERVAL_UNIT_* constants.
1298
     *
1299
     * @return string
1300
     *
1301
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1302
     */
1303
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
1304
    {
1305
        throw DBALException::notSupported(__METHOD__);
1306
    }
1307
1308
    /**
1309
     * Returns the SQL bit AND comparison expression.
1310
     *
1311
     * @param string $value1
1312
     * @param string $value2
1313
     *
1314
     * @return string
1315
     */
1316 15
    public function getBitAndComparisonExpression($value1, $value2)
1317
    {
1318 15
        return '(' . $value1 . ' & ' . $value2 . ')';
1319
    }
1320
1321
    /**
1322
     * Returns the SQL bit OR comparison expression.
1323
     *
1324
     * @param string $value1
1325
     * @param string $value2
1326
     *
1327
     * @return string
1328
     */
1329 15
    public function getBitOrComparisonExpression($value1, $value2)
1330
    {
1331 15
        return '(' . $value1 . ' | ' . $value2 . ')';
1332
    }
1333
1334
    /**
1335
     * Returns the FOR UPDATE expression.
1336
     *
1337
     * @return string
1338
     */
1339
    public function getForUpdateSQL()
1340
    {
1341
        return 'FOR UPDATE';
1342
    }
1343
1344
    /**
1345
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1346
     *
1347
     * @param string       $fromClause The FROM clause to append the hint for the given lock mode to.
1348
     * @param integer|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1349
     *                                 be appended to the FROM clause.
1350
     *
1351
     * @return string
1352
     */
1353
    public function appendLockHint($fromClause, $lockMode)
1354
    {
1355
        return $fromClause;
1356
    }
1357
1358
    /**
1359
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1360
     *
1361
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1362
     * vendors allow to lighten this constraint up to be a real read lock.
1363
     *
1364
     * @return string
1365
     */
1366
    public function getReadLockSQL()
1367
    {
1368
        return $this->getForUpdateSQL();
1369
    }
1370
1371
    /**
1372
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1373
     *
1374
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1375
     *
1376
     * @return string
1377
     */
1378
    public function getWriteLockSQL()
1379
    {
1380
        return $this->getForUpdateSQL();
1381
    }
1382
1383
    /**
1384
     * Returns the SQL snippet to drop an existing database.
1385
     *
1386
     * @param string $database The name of the database that should be dropped.
1387
     *
1388
     * @return string
1389
     */
1390 4
    public function getDropDatabaseSQL($database)
1391
    {
1392 4
        return 'DROP DATABASE ' . $database;
1393
    }
1394
1395
    /**
1396
     * Returns the SQL snippet to drop an existing table.
1397
     *
1398
     * @param \Doctrine\DBAL\Schema\Table|string $table
1399
     *
1400
     * @return string
1401
     *
1402
     * @throws \InvalidArgumentException
1403
     */
1404 102
    public function getDropTableSQL($table)
1405
    {
1406 102
        $tableArg = $table;
1407
1408 102
        if ($table instanceof Table) {
1409 27
            $table = $table->getQuotedName($this);
1410 87
        } elseif (!is_string($table)) {
1411
            throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1412
        }
1413
1414 102
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1415 16
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1416 16
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1417
1418 16
            if ($eventArgs->isDefaultPrevented()) {
1419
                return $eventArgs->getSql();
1420
            }
1421
        }
1422
1423 102
        return 'DROP TABLE ' . $table;
1424
    }
1425
1426
    /**
1427
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1428
     *
1429
     * @param \Doctrine\DBAL\Schema\Table|string $table
1430
     *
1431
     * @return string
1432
     */
1433 2
    public function getDropTemporaryTableSQL($table)
1434
    {
1435 2
        return $this->getDropTableSQL($table);
1436
    }
1437
1438
    /**
1439
     * Returns the SQL to drop an index from a table.
1440
     *
1441
     * @param \Doctrine\DBAL\Schema\Index|string $index
1442
     * @param \Doctrine\DBAL\Schema\Table|string $table
1443
     *
1444
     * @return string
1445
     *
1446
     * @throws \InvalidArgumentException
1447
     */
1448 9 View Code Duplication
    public function getDropIndexSQL($index, $table = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1449
    {
1450 9
        if ($index instanceof Index) {
1451 8
            $index = $index->getQuotedName($this);
1452 1
        } elseif (!is_string($index)) {
1453
            throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1454
        }
1455
1456 9
        return 'DROP INDEX ' . $index;
1457
    }
1458
1459
    /**
1460
     * Returns the SQL to drop a constraint.
1461
     *
1462
     * @param \Doctrine\DBAL\Schema\Constraint|string $constraint
1463
     * @param \Doctrine\DBAL\Schema\Table|string      $table
1464
     *
1465
     * @return string
1466
     */
1467 31 View Code Duplication
    public function getDropConstraintSQL($constraint, $table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1468
    {
1469 31
        if (! $constraint instanceof Constraint) {
1470 23
            $constraint = new Identifier($constraint);
1471
        }
1472
1473 31
        if (! $table instanceof Table) {
1474 31
            $table = new Identifier($table);
1475
        }
1476
1477 31
        $constraint = $constraint->getQuotedName($this);
1478 31
        $table = $table->getQuotedName($this);
1479
1480 31
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1481
    }
1482
1483
    /**
1484
     * Returns the SQL to drop a foreign key.
1485
     *
1486
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint|string $foreignKey
1487
     * @param \Doctrine\DBAL\Schema\Table|string                $table
1488
     *
1489
     * @return string
1490
     */
1491 17 View Code Duplication
    public function getDropForeignKeySQL($foreignKey, $table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1492
    {
1493 17
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1494 7
            $foreignKey = new Identifier($foreignKey);
1495
        }
1496
1497 17
        if (! $table instanceof Table) {
1498 17
            $table = new Identifier($table);
1499
        }
1500
1501 17
        $foreignKey = $foreignKey->getQuotedName($this);
1502 17
        $table = $table->getQuotedName($this);
1503
1504 17
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1505
    }
1506
1507
    /**
1508
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1509
     * on this platform.
1510
     *
1511
     * @param \Doctrine\DBAL\Schema\Table   $table
1512
     * @param integer                       $createFlags
1513
     *
1514
     * @return array The sequence of SQL statements.
1515
     *
1516
     * @throws \Doctrine\DBAL\DBALException
1517
     * @throws \InvalidArgumentException
1518
     */
1519 350
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1520
    {
1521 350
        if ( ! is_int($createFlags)) {
1522
            throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
1523
        }
1524
1525 350
        if (count($table->getColumns()) === 0) {
1526 16
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1527
        }
1528
1529 334
        $tableName = $table->getQuotedName($this);
1530 334
        $options = $table->getOptions();
1531 334
        $options['uniqueConstraints'] = array();
1532 334
        $options['indexes'] = array();
1533 334
        $options['primary'] = array();
1534
1535 334
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1536 313
            foreach ($table->getIndexes() as $index) {
1537
                /* @var $index Index */
1538 232
                if ($index->isPrimary()) {
1539 175
                    $options['primary']       = $index->getQuotedColumns($this);
1540 175
                    $options['primary_index'] = $index;
1541
                } else {
1542 70
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1543
                }
1544
            }
1545
        }
1546
1547 334
        $columnSql = array();
1548 334
        $columns = array();
1549
1550 334
        foreach ($table->getColumns() as $column) {
1551
            /* @var \Doctrine\DBAL\Schema\Column $column */
1552
1553 334 View Code Duplication
            if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1554 16
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1555 16
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1556
1557 16
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1558
1559 16
                if ($eventArgs->isDefaultPrevented()) {
1560
                    continue;
1561
                }
1562
            }
1563
1564 334
            $columnData = $column->toArray();
1565 334
            $columnData['name'] = $column->getQuotedName($this);
1566 334
            $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false;
1567 334
            $columnData['comment'] = $this->getColumnComment($column);
1568
1569 334
            if (strtolower($columnData['type']) == "string" && $columnData['length'] === null) {
1570 134
                $columnData['length'] = 255;
1571
            }
1572
1573 334
            if (in_array($column->getName(), $options['primary'])) {
1574 157
                $columnData['primary'] = true;
1575
            }
1576
1577 334
            $columns[$columnData['name']] = $columnData;
1578
        }
1579
1580 334
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1581 168
            $options['foreignKeys'] = array();
1582 168
            foreach ($table->getForeignKeys() as $fkConstraint) {
1583 28
                $options['foreignKeys'][] = $fkConstraint;
1584
            }
1585
        }
1586
1587 334 View Code Duplication
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1588 16
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1589 16
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1590
1591 16
            if ($eventArgs->isDefaultPrevented()) {
1592
                return array_merge($eventArgs->getSql(), $columnSql);
1593
            }
1594
        }
1595
1596 334
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1597 334
        if ($this->supportsCommentOnStatement()) {
1598 111
            foreach ($table->getColumns() as $column) {
1599 111
                $comment = $this->getColumnComment($column);
1600
1601 111 View Code Duplication
                if (null !== $comment && '' !== $comment) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1602 20
                    $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1603
                }
1604
            }
1605
        }
1606
1607 334
        return array_merge($sql, $columnSql);
1608
    }
1609
1610
    /**
1611
     * @param string $tableName
1612
     * @param string $columnName
1613
     * @param string $comment
1614
     *
1615
     * @return string
1616
     */
1617 31 View Code Duplication
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1618
    {
1619 31
        $tableName = new Identifier($tableName);
1620 31
        $columnName = new Identifier($columnName);
1621 31
        $comment = $this->quoteStringLiteral($comment);
1622
1623 31
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . "." . $columnName->getQuotedName($this) .
1624 31
            " IS " . $comment;
1625
    }
1626
1627
    /**
1628
     * Returns the SQL to create inline comment on a column.
1629
     *
1630
     * @param string $comment
1631
     *
1632
     * @return string
1633
     *
1634
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1635
     */
1636 31
    public function getInlineColumnCommentSQL($comment)
1637
    {
1638 31
        if (! $this->supportsInlineColumnComments()) {
1639 13
            throw DBALException::notSupported(__METHOD__);
1640
        }
1641
1642 18
        return "COMMENT " . $this->quoteStringLiteral($comment);
1643
    }
1644
1645
    /**
1646
     * Returns the SQL used to create a table.
1647
     *
1648
     * @param string $tableName
1649
     * @param array  $columns
1650
     * @param array  $options
1651
     *
1652
     * @return array
1653
     */
1654 23
    protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
1655
    {
1656 23
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1657
1658 23
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1659
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1660
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1661
            }
1662
        }
1663
1664 23 View Code Duplication
        if (isset($options['primary']) && ! empty($options['primary'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1665 10
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1666
        }
1667
1668 23
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1669
            foreach ($options['indexes'] as $index => $definition) {
1670
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1671
            }
1672
        }
1673
1674 23
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1675
1676 23
        $check = $this->getCheckDeclarationSQL($columns);
1677 23
        if ( ! empty($check)) {
1678 1
            $query .= ', ' . $check;
1679
        }
1680 23
        $query .= ')';
1681
1682 23
        $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...
1683
1684 23 View Code Duplication
        if (isset($options['foreignKeys'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1685 3
            foreach ((array) $options['foreignKeys'] as $definition) {
1686 3
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1687
            }
1688
        }
1689
1690 23
        return $sql;
1691
    }
1692
1693
    /**
1694
     * @return string
1695
     */
1696 2
    public function getCreateTemporaryTableSnippetSQL()
1697
    {
1698 2
        return "CREATE TEMPORARY TABLE";
1699
    }
1700
1701
    /**
1702
     * Returns the SQL to create a sequence on this platform.
1703
     *
1704
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1705
     *
1706
     * @return string
1707
     *
1708
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1709
     */
1710
    public function getCreateSequenceSQL(Sequence $sequence)
1711
    {
1712
        throw DBALException::notSupported(__METHOD__);
1713
    }
1714
1715
    /**
1716
     * Returns the SQL to change a sequence on this platform.
1717
     *
1718
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1719
     *
1720
     * @return string
1721
     *
1722
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1723
     */
1724
    public function getAlterSequenceSQL(Sequence $sequence)
1725
    {
1726
        throw DBALException::notSupported(__METHOD__);
1727
    }
1728
1729
    /**
1730
     * Returns the SQL to create a constraint on a table on this platform.
1731
     *
1732
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1733
     * @param \Doctrine\DBAL\Schema\Table|string $table
1734
     *
1735
     * @return string
1736
     *
1737
     * @throws \InvalidArgumentException
1738
     */
1739 14
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1740
    {
1741 14
        if ($table instanceof Table) {
1742
            $table = $table->getQuotedName($this);
1743
        }
1744
1745 14
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1746
1747 14
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1748
1749 14
        $referencesClause = '';
1750 14
        if ($constraint instanceof Index) {
1751 14
            if ($constraint->isPrimary()) {
1752 14
                $query .= ' PRIMARY KEY';
1753 11
            } elseif ($constraint->isUnique()) {
1754 11
                $query .= ' UNIQUE';
1755
            } else {
1756
                throw new \InvalidArgumentException(
1757
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1758
                );
1759
            }
1760 11
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1761 11
            $query .= ' FOREIGN KEY';
1762
1763 11
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1764 11
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1765
        }
1766 14
        $query .= ' '.$columnList.$referencesClause;
1767
1768 14
        return $query;
1769
    }
1770
1771
    /**
1772
     * Returns the SQL to create an index on a table on this platform.
1773
     *
1774
     * @param \Doctrine\DBAL\Schema\Index        $index
1775
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1776
     *
1777
     * @return string
1778
     *
1779
     * @throws \InvalidArgumentException
1780
     */
1781 135
    public function getCreateIndexSQL(Index $index, $table)
1782
    {
1783 135
        if ($table instanceof Table) {
1784 1
            $table = $table->getQuotedName($this);
1785
        }
1786 135
        $name = $index->getQuotedName($this);
1787 135
        $columns = $index->getQuotedColumns($this);
1788
1789 135
        if (count($columns) == 0) {
1790
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1791
        }
1792
1793 135
        if ($index->isPrimary()) {
1794 16
            return $this->getCreatePrimaryKeySQL($index, $table);
1795
        }
1796
1797 121
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1798 121
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index);
1799
1800 121
        return $query;
1801
    }
1802
1803
    /**
1804
     * Adds condition for partial index.
1805
     *
1806
     * @param \Doctrine\DBAL\Schema\Index $index
1807
     *
1808
     * @return string
1809
     */
1810 158
    protected function getPartialIndexSQL(Index $index)
1811
    {
1812 158
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1813 4
            return  ' WHERE ' . $index->getOption('where');
1814
        }
1815
1816 154
        return '';
1817
    }
1818
1819
    /**
1820
     * Adds additional flags for index generation.
1821
     *
1822
     * @param \Doctrine\DBAL\Schema\Index $index
1823
     *
1824
     * @return string
1825
     */
1826 60
    protected function getCreateIndexSQLFlags(Index $index)
1827
    {
1828 60
        return $index->isUnique() ? 'UNIQUE ' : '';
1829
    }
1830
1831
    /**
1832
     * Returns the SQL to create an unnamed primary key constraint.
1833
     *
1834
     * @param \Doctrine\DBAL\Schema\Index        $index
1835
     * @param \Doctrine\DBAL\Schema\Table|string $table
1836
     *
1837
     * @return string
1838
     */
1839 12
    public function getCreatePrimaryKeySQL(Index $index, $table)
1840
    {
1841 12
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
1842
    }
1843
1844
    /**
1845
     * Returns the SQL to create a named schema.
1846
     *
1847
     * @param string $schemaName
1848
     *
1849
     * @return string
1850
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1851
     */
1852 9
    public function getCreateSchemaSQL($schemaName)
1853
    {
1854 9
        throw DBALException::notSupported(__METHOD__);
1855
    }
1856
1857
    /**
1858
     * Quotes a string so that it can be safely used as a table or column name,
1859
     * even if it is a reserved word of the platform. This also detects identifier
1860
     * chains separated by dot and quotes them independently.
1861
     *
1862
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1863
     * you SHOULD use them. In general, they end up causing way more
1864
     * problems than they solve.
1865
     *
1866
     * @param string $str The identifier name to be quoted.
1867
     *
1868
     * @return string The quoted identifier string.
1869
     */
1870 348
    public function quoteIdentifier($str)
1871
    {
1872 348
        if (strpos($str, ".") !== false) {
1873 16
            $parts = array_map(array($this, "quoteSingleIdentifier"), explode(".", $str));
1874
1875 16
            return implode(".", $parts);
1876
        }
1877
1878 348
        return $this->quoteSingleIdentifier($str);
1879
    }
1880
1881
    /**
1882
     * Quotes a single identifier (no dot chain separation).
1883
     *
1884
     * @param string $str The identifier name to be quoted.
1885
     *
1886
     * @return string The quoted identifier string.
1887
     */
1888 318
    public function quoteSingleIdentifier($str)
1889
    {
1890 318
        $c = $this->getIdentifierQuoteCharacter();
1891
1892 318
        return $c . str_replace($c, $c.$c, $str) . $c;
1893
    }
1894
1895
    /**
1896
     * Returns the SQL to create a new foreign key.
1897
     *
1898
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key constraint.
1899
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
1900
     *
1901
     * @return string
1902
     */
1903 67
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1904
    {
1905 67
        if ($table instanceof Table) {
1906 1
            $table = $table->getQuotedName($this);
1907
        }
1908
1909 67
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1910
1911 67
        return $query;
1912
    }
1913
1914
    /**
1915
     * Gets the SQL statements for altering an existing table.
1916
     *
1917
     * This method returns an array of SQL statements, since some platforms need several statements.
1918
     *
1919
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1920
     *
1921
     * @return array
1922
     *
1923
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1924
     */
1925
    public function getAlterTableSQL(TableDiff $diff)
1926
    {
1927
        throw DBALException::notSupported(__METHOD__);
1928
    }
1929
1930
    /**
1931
     * @param \Doctrine\DBAL\Schema\Column    $column
1932
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1933
     * @param array                           $columnSql
1934
     *
1935
     * @return boolean
1936
     */
1937 85 View Code Duplication
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1938
    {
1939 85
        if (null === $this->_eventManager) {
1940 68
            return false;
1941
        }
1942
1943 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1944 1
            return false;
1945
        }
1946
1947 16
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1948 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1949
1950 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1951
1952 16
        return $eventArgs->isDefaultPrevented();
1953
    }
1954
1955
    /**
1956
     * @param \Doctrine\DBAL\Schema\Column    $column
1957
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1958
     * @param array                           $columnSql
1959
     *
1960
     * @return boolean
1961
     */
1962 69 View Code Duplication
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1963
    {
1964 69
        if (null === $this->_eventManager) {
1965 52
            return false;
1966
        }
1967
1968 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
1969 1
            return false;
1970
        }
1971
1972 16
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
1973 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
1974
1975 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1976
1977 16
        return $eventArgs->isDefaultPrevented();
1978
    }
1979
1980
    /**
1981
     * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff
1982
     * @param \Doctrine\DBAL\Schema\TableDiff  $diff
1983
     * @param array                            $columnSql
1984
     *
1985
     * @return boolean
1986
     */
1987 168 View Code Duplication
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1988
    {
1989 168
        if (null === $this->_eventManager) {
1990 140
            return false;
1991
        }
1992
1993 28
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
1994 12
            return false;
1995
        }
1996
1997 16
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
1998 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
1999
2000 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2001
2002 16
        return $eventArgs->isDefaultPrevented();
2003
    }
2004
2005
    /**
2006
     * @param string                          $oldColumnName
2007
     * @param \Doctrine\DBAL\Schema\Column    $column
2008
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2009
     * @param array                           $columnSql
2010
     *
2011
     * @return boolean
2012
     */
2013 68 View Code Duplication
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2014
    {
2015 68
        if (null === $this->_eventManager) {
2016 52
            return false;
2017
        }
2018
2019 16
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2020
            return false;
2021
        }
2022
2023 16
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2024 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2025
2026 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2027
2028 16
        return $eventArgs->isDefaultPrevented();
2029
    }
2030
2031
    /**
2032
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2033
     * @param array                           $sql
2034
     *
2035
     * @return boolean
2036
     */
2037 315 View Code Duplication
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2038
    {
2039 315
        if (null === $this->_eventManager) {
2040 280
            return false;
2041
        }
2042
2043 35
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2044 19
            return false;
2045
        }
2046
2047 16
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2048 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2049
2050 16
        $sql = array_merge($sql, $eventArgs->getSql());
2051
2052 16
        return $eventArgs->isDefaultPrevented();
2053
    }
2054
2055
    /**
2056
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2057
     *
2058
     * @return array
2059
     */
2060 283
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2061
    {
2062 283
        $tableName = $diff->getName($this)->getQuotedName($this);
2063
2064 283
        $sql = array();
2065 283 View Code Duplication
        if ($this->supportsForeignKeyConstraints()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2066 283
            foreach ($diff->removedForeignKeys as $foreignKey) {
2067 21
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2068
            }
2069 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2070 17
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2071
            }
2072
        }
2073
2074 283
        foreach ($diff->removedIndexes as $index) {
2075 8
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2076
        }
2077 283
        foreach ($diff->changedIndexes as $index) {
2078 11
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2079
        }
2080
2081 283
        return $sql;
2082
    }
2083
2084
    /**
2085
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2086
     *
2087
     * @return array
2088
     */
2089 283
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2090
    {
2091 283
        $tableName = (false !== $diff->newName)
2092 30
            ? $diff->getNewName()->getQuotedName($this)
2093 283
            : $diff->getName($this)->getQuotedName($this);
2094
2095 283
        $sql = array();
2096
2097 283 View Code Duplication
        if ($this->supportsForeignKeyConstraints()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2098 283
            foreach ($diff->addedForeignKeys as $foreignKey) {
2099 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2100
            }
2101
2102 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2103 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2104
            }
2105
        }
2106
2107 283
        foreach ($diff->addedIndexes as $index) {
2108 2
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2109
        }
2110
2111 283
        foreach ($diff->changedIndexes as $index) {
2112 11
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2113
        }
2114
2115 283
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2116 75
            $oldIndexName = new Identifier($oldIndexName);
2117 75
            $sql          = array_merge(
2118 75
                $sql,
2119 75
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2120
            );
2121
        }
2122
2123 283
        return $sql;
2124
    }
2125
2126
    /**
2127
     * Returns the SQL for renaming an index on a table.
2128
     *
2129
     * @param string                      $oldIndexName The name of the index to rename from.
2130
     * @param \Doctrine\DBAL\Schema\Index $index        The definition of the index to rename to.
2131
     * @param string                      $tableName    The table to rename the given index on.
2132
     *
2133
     * @return array The sequence of SQL statements for renaming the given index.
2134
     */
2135 5
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2136
    {
2137
        return array(
2138 5
            $this->getDropIndexSQL($oldIndexName, $tableName),
2139 5
            $this->getCreateIndexSQL($index, $tableName)
2140
        );
2141
    }
2142
2143
    /**
2144
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2145
     *
2146
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2147
     *
2148
     * @return array
2149
     */
2150
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2151
    {
2152
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2153
    }
2154
2155
    /**
2156
     * Gets declaration of a number of fields in bulk.
2157
     *
2158
     * @param array $fields A multidimensional associative array.
2159
     *                      The first dimension determines the field name, while the second
2160
     *                      dimension is keyed with the name of the properties
2161
     *                      of the field being declared as array indexes. Currently, the types
2162
     *                      of supported field properties are as follows:
2163
     *
2164
     *      length
2165
     *          Integer value that determines the maximum length of the text
2166
     *          field. If this argument is missing the field should be
2167
     *          declared to have the longest length allowed by the DBMS.
2168
     *
2169
     *      default
2170
     *          Text value to be used as default for this field.
2171
     *
2172
     *      notnull
2173
     *          Boolean flag that indicates whether this field is constrained
2174
     *          to not be set to null.
2175
     *      charset
2176
     *          Text value with the default CHARACTER SET for this field.
2177
     *      collation
2178
     *          Text value with the default COLLATION for this field.
2179
     *      unique
2180
     *          unique constraint
2181
     *
2182
     * @return string
2183
     */
2184 334
    public function getColumnDeclarationListSQL(array $fields)
2185
    {
2186 334
        $queryFields = array();
2187
2188 334
        foreach ($fields as $fieldName => $field) {
2189 334
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2190
        }
2191
2192 334
        return implode(', ', $queryFields);
2193
    }
2194
2195
    /**
2196
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2197
     * field to be used in statements like CREATE TABLE.
2198
     *
2199
     * @param string $name  The name the field to be declared.
2200
     * @param array  $field An associative array with the name of the properties
2201
     *                      of the field being declared as array indexes. Currently, the types
2202
     *                      of supported field properties are as follows:
2203
     *
2204
     *      length
2205
     *          Integer value that determines the maximum length of the text
2206
     *          field. If this argument is missing the field should be
2207
     *          declared to have the longest length allowed by the DBMS.
2208
     *
2209
     *      default
2210
     *          Text value to be used as default for this field.
2211
     *
2212
     *      notnull
2213
     *          Boolean flag that indicates whether this field is constrained
2214
     *          to not be set to null.
2215
     *      charset
2216
     *          Text value with the default CHARACTER SET for this field.
2217
     *      collation
2218
     *          Text value with the default COLLATION for this field.
2219
     *      unique
2220
     *          unique constraint
2221
     *      check
2222
     *          column check constraint
2223
     *      columnDefinition
2224
     *          a string that defines the complete column
2225
     *
2226
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2227
     */
2228 364
    public function getColumnDeclarationSQL($name, array $field)
2229
    {
2230 364
        if (isset($field['columnDefinition'])) {
2231 13
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2232
        } else {
2233 352
            $default = $this->getDefaultValueDeclarationSQL($field);
2234
2235 352
            $charset = (isset($field['charset']) && $field['charset']) ?
2236 352
                    ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2237
2238 352
            $collation = (isset($field['collation']) && $field['collation']) ?
2239 352
                    ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2240
2241 352
            $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
2242
2243 352
            $unique = (isset($field['unique']) && $field['unique']) ?
2244 352
                    ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2245
2246 352
            $check = (isset($field['check']) && $field['check']) ?
2247 352
                    ' ' . $field['check'] : '';
2248
2249 352
            $typeDecl = $field['type']->getSQLDeclaration($field, $this);
2250 352
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2251
2252 352
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2253 45
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2254
            }
2255
        }
2256
2257 364
        return $name . ' ' . $columnDef;
2258
    }
2259
2260
    /**
2261
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2262
     *
2263
     * @param array $columnDef
2264
     *
2265
     * @return string
2266
     */
2267 120
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2268
    {
2269 120
        $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
2270 120
            ? 10 : $columnDef['precision'];
2271 120
        $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
2272 120
            ? 0 : $columnDef['scale'];
2273
2274 120
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2275
    }
2276
2277
    /**
2278
     * Obtains DBMS specific SQL code portion needed to set a default value
2279
     * declaration to be used in statements like CREATE TABLE.
2280
     *
2281
     * @param array $field The field definition array.
2282
     *
2283
     * @return string DBMS specific SQL code portion needed to set a default value.
2284
     */
2285 410
    public function getDefaultValueDeclarationSQL($field)
2286
    {
2287 410
        $default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
2288
2289 410
        if (isset($field['default'])) {
2290 64
            $default = " DEFAULT '".$field['default']."'";
2291 64
            if (isset($field['type'])) {
2292 64
                if (in_array((string) $field['type'], array("Integer", "BigInt", "SmallInt"))) {
2293 20
                    $default = " DEFAULT ".$field['default'];
2294 46 View Code Duplication
                } elseif (in_array((string) $field['type'], array('DateTime', 'DateTimeTz')) && $field['default'] == $this->getCurrentTimestampSQL()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2295 13
                    $default = " DEFAULT ".$this->getCurrentTimestampSQL();
2296 33
                } elseif ((string) $field['type'] == 'Time' && $field['default'] == $this->getCurrentTimeSQL()) {
2297
                    $default = " DEFAULT ".$this->getCurrentTimeSQL();
2298 33
                } elseif ((string) $field['type'] == 'Date' && $field['default'] == $this->getCurrentDateSQL()) {
2299
                    $default = " DEFAULT ".$this->getCurrentDateSQL();
2300 33 View Code Duplication
                } elseif ((string) $field['type'] == 'Boolean') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2301 13
                    $default = " DEFAULT '" . $this->convertBooleans($field['default']) . "'";
2302
                }
2303
            }
2304
        }
2305
2306 410
        return $default;
2307
    }
2308
2309
    /**
2310
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2311
     * declaration to be used in statements like CREATE TABLE.
2312
     *
2313
     * @param array $definition The check definition.
2314
     *
2315
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2316
     */
2317 117
    public function getCheckDeclarationSQL(array $definition)
2318
    {
2319 117
        $constraints = array();
2320 117
        foreach ($definition as $field => $def) {
2321 117
            if (is_string($def)) {
2322
                $constraints[] = 'CHECK (' . $def . ')';
2323
            } else {
2324 117 View Code Duplication
                if (isset($def['min'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2325 5
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2326
                }
2327
2328 117 View Code Duplication
                if (isset($def['max'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2329 5
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2330
                }
2331
            }
2332
        }
2333
2334 117
        return implode(', ', $constraints);
2335
    }
2336
2337
    /**
2338
     * Obtains DBMS specific SQL code portion needed to set a unique
2339
     * constraint declaration to be used in statements like CREATE TABLE.
2340
     *
2341
     * @param string                      $name  The name of the unique constraint.
2342
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2343
     *
2344
     * @return string DBMS specific SQL code portion needed to set a constraint.
2345
     *
2346
     * @throws \InvalidArgumentException
2347
     */
2348 24 View Code Duplication
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2349
    {
2350 24
        $columns = $index->getQuotedColumns($this);
2351 24
        $name = new Identifier($name);
2352
2353 24
        if (count($columns) === 0) {
2354
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2355
        }
2356
2357 24
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2358 24
             . $this->getIndexFieldDeclarationListSQL($columns)
2359 24
             . ')' . $this->getPartialIndexSQL($index);
2360
    }
2361
2362
    /**
2363
     * Obtains DBMS specific SQL code portion needed to set an index
2364
     * declaration to be used in statements like CREATE TABLE.
2365
     *
2366
     * @param string                      $name  The name of the index.
2367
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2368
     *
2369
     * @return string DBMS specific SQL code portion needed to set an index.
2370
     *
2371
     * @throws \InvalidArgumentException
2372
     */
2373 36 View Code Duplication
    public function getIndexDeclarationSQL($name, Index $index)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2374
    {
2375 36
        $columns = $index->getQuotedColumns($this);
2376 36
        $name = new Identifier($name);
2377
2378 36
        if (count($columns) === 0) {
2379
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2380
        }
2381
2382 36
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2383 36
            . $this->getIndexFieldDeclarationListSQL($columns)
2384 36
            . ')' . $this->getPartialIndexSQL($index);
2385
    }
2386
2387
    /**
2388
     * Obtains SQL code portion needed to create a custom column,
2389
     * e.g. when a field has the "columnDefinition" keyword.
2390
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2391
     *
2392
     * @param array $columnDef
2393
     *
2394
     * @return string
2395
     */
2396 17
    public function getCustomTypeDeclarationSQL(array $columnDef)
2397
    {
2398 17
        return $columnDef['columnDefinition'];
2399
    }
2400
2401
    /**
2402
     * Obtains DBMS specific SQL code portion needed to set an index
2403
     * declaration to be used in statements like CREATE TABLE.
2404
     *
2405
     * @param array $fields
2406
     *
2407
     * @return string
2408
     */
2409 222
    public function getIndexFieldDeclarationListSQL(array $fields)
2410
    {
2411 222
        $ret = array();
2412
2413 222
        foreach ($fields as $field => $definition) {
2414 222
            if (is_array($definition)) {
2415
                $ret[] = $field;
2416
            } else {
2417 222
                $ret[] = $definition;
2418
            }
2419
        }
2420
2421 222
        return implode(', ', $ret);
2422
    }
2423
2424
    /**
2425
     * Returns the required SQL string that fits between CREATE ... TABLE
2426
     * to create the table as a temporary table.
2427
     *
2428
     * Should be overridden in driver classes to return the correct string for the
2429
     * specific database type.
2430
     *
2431
     * The default is to return the string "TEMPORARY" - this will result in a
2432
     * SQL error for any database that does not support temporary tables, or that
2433
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2434
     *
2435
     * @return string The string required to be placed between "CREATE" and "TABLE"
2436
     *                to generate a temporary table, if possible.
2437
     */
2438
    public function getTemporaryTableSQL()
2439
    {
2440
        return 'TEMPORARY';
2441
    }
2442
2443
    /**
2444
     * Some vendors require temporary table names to be qualified specially.
2445
     *
2446
     * @param string $tableName
2447
     *
2448
     * @return string
2449
     */
2450
    public function getTemporaryTableName($tableName)
2451
    {
2452
        return $tableName;
2453
    }
2454
2455
    /**
2456
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2457
     * of a field declaration to be used in statements like CREATE TABLE.
2458
     *
2459
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2460
     *
2461
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2462
     *                of a field declaration.
2463
     */
2464 101
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2465
    {
2466 101
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2467 89
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2468
2469 89
        return $sql;
2470
    }
2471
2472
    /**
2473
     * Returns the FOREIGN KEY query section dealing with non-standard options
2474
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2475
     *
2476
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key definition.
2477
     *
2478
     * @return string
2479
     */
2480 85
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2481
    {
2482 85
        $query = '';
2483 85
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2484 4
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2485
        }
2486 85
        if ($foreignKey->hasOption('onDelete')) {
2487 8
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2488
        }
2489
2490 85
        return $query;
2491
    }
2492
2493
    /**
2494
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2495
     *
2496
     * @param string $action The foreign key referential action.
2497
     *
2498
     * @return string
2499
     *
2500
     * @throws \InvalidArgumentException if unknown referential action given
2501
     */
2502 106 View Code Duplication
    public function getForeignKeyReferentialActionSQL($action)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2503
    {
2504 106
        $upper = strtoupper($action);
2505
        switch ($upper) {
2506 106
            case 'CASCADE':
2507 72
            case 'SET NULL':
2508 53
            case 'NO ACTION':
2509 42
            case 'RESTRICT':
2510 30
            case 'SET DEFAULT':
2511 91
                return $upper;
2512
            default:
2513 15
                throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper);
2514
        }
2515
    }
2516
2517
    /**
2518
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2519
     * of a field declaration to be used in statements like CREATE TABLE.
2520
     *
2521
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2522
     *
2523
     * @return string
2524
     *
2525
     * @throws \InvalidArgumentException
2526
     */
2527 61
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2528
    {
2529 61
        $sql = '';
2530 61
        if (strlen($foreignKey->getName())) {
2531 49
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2532
        }
2533 61
        $sql .= 'FOREIGN KEY (';
2534
2535 61
        if (count($foreignKey->getLocalColumns()) === 0) {
2536
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
2537
        }
2538 61
        if (count($foreignKey->getForeignColumns()) === 0) {
2539
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
2540
        }
2541 61
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2542
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2543
        }
2544
2545 61
        $sql .= implode(', ', $foreignKey->getQuotedLocalColumns($this))
2546 61
              . ') REFERENCES '
2547 61
              . $foreignKey->getQuotedForeignTableName($this) . ' ('
2548 61
              . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2549
2550 61
        return $sql;
2551
    }
2552
2553
    /**
2554
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2555
     * of a field declaration to be used in statements like CREATE TABLE.
2556
     *
2557
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2558
     *                of a field declaration.
2559
     */
2560
    public function getUniqueFieldDeclarationSQL()
2561
    {
2562
        return 'UNIQUE';
2563
    }
2564
2565
    /**
2566
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2567
     * of a field declaration to be used in statements like CREATE TABLE.
2568
     *
2569
     * @param string $charset The name of the charset.
2570
     *
2571
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2572
     *                of a field declaration.
2573
     */
2574
    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...
2575
    {
2576
        return '';
2577
    }
2578
2579
    /**
2580
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2581
     * of a field declaration to be used in statements like CREATE TABLE.
2582
     *
2583
     * @param string $collation The name of the collation.
2584
     *
2585
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2586
     *                of a field declaration.
2587
     */
2588 1
    public function getColumnCollationDeclarationSQL($collation)
2589
    {
2590 1
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2591
    }
2592
2593
    /**
2594
     * Whether the platform prefers sequences for ID generation.
2595
     * Subclasses should override this method to return TRUE if they prefer sequences.
2596
     *
2597
     * @return boolean
2598
     */
2599 5
    public function prefersSequences()
2600
    {
2601 5
        return false;
2602
    }
2603
2604
    /**
2605
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2606
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2607
     *
2608
     * @return boolean
2609
     */
2610 5
    public function prefersIdentityColumns()
2611
    {
2612 5
        return false;
2613
    }
2614
2615
    /**
2616
     * Some platforms need the boolean values to be converted.
2617
     *
2618
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2619
     *
2620
     * Note: if the input is not a boolean the original input might be returned.
2621
     *
2622
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2623
     * This method should handle the literal case
2624
     *
2625
     * @param mixed $item A boolean or an array of them.
2626
     *
2627
     * @return mixed A boolean database value or an array of them.
2628
     */
2629 20
    public function convertBooleans($item)
2630
    {
2631 20
        if (is_array($item)) {
2632
            foreach ($item as $k => $value) {
2633
                if (is_bool($value)) {
2634
                    $item[$k] = (int) $value;
2635
                }
2636
            }
2637 20
        } elseif (is_bool($item)) {
2638 19
            $item = (int) $item;
2639
        }
2640
2641 20
        return $item;
2642
    }
2643
2644
    /**
2645
     * Some platforms have boolean literals that needs to be correctly converted
2646
     *
2647
     * The default conversion tries to convert value into bool "(bool)$item"
2648
     *
2649
     * @param mixed $item
2650
     *
2651
     * @return bool|null
2652
     */
2653 40
    public function convertFromBoolean($item)
2654
    {
2655 40
        return null === $item ? null: (bool) $item ;
2656
    }
2657
2658
    /**
2659
     * This method should handle the prepared statements case. When there is no
2660
     * distinction, it's OK to use the same method.
2661
     *
2662
     * Note: if the input is not a boolean the original input might be returned.
2663
     *
2664
     * @param mixed $item A boolean or an array of them.
2665
     *
2666
     * @return mixed A boolean database value or an array of them.
2667
     */
2668 7
    public function convertBooleansToDatabaseValue($item)
2669
    {
2670 7
        return $this->convertBooleans($item);
2671
    }
2672
2673
    /**
2674
     * Returns the SQL specific for the platform to get the current date.
2675
     *
2676
     * @return string
2677
     */
2678 1
    public function getCurrentDateSQL()
2679
    {
2680 1
        return 'CURRENT_DATE';
2681
    }
2682
2683
    /**
2684
     * Returns the SQL specific for the platform to get the current time.
2685
     *
2686
     * @return string
2687
     */
2688
    public function getCurrentTimeSQL()
2689
    {
2690
        return 'CURRENT_TIME';
2691
    }
2692
2693
    /**
2694
     * Returns the SQL specific for the platform to get the current timestamp
2695
     *
2696
     * @return string
2697
     */
2698 15
    public function getCurrentTimestampSQL()
2699
    {
2700 15
        return 'CURRENT_TIMESTAMP';
2701
    }
2702
2703
    /**
2704
     * Returns the SQL for a given transaction isolation level Connection constant.
2705
     *
2706
     * @param integer $level
2707
     *
2708
     * @return string
2709
     *
2710
     * @throws \InvalidArgumentException
2711
     */
2712 9
    protected function _getTransactionIsolationLevelSQL($level)
2713
    {
2714
        switch ($level) {
2715 9
            case Connection::TRANSACTION_READ_UNCOMMITTED:
2716 9
                return 'READ UNCOMMITTED';
2717 9
            case Connection::TRANSACTION_READ_COMMITTED:
2718 9
                return 'READ COMMITTED';
2719 9
            case Connection::TRANSACTION_REPEATABLE_READ:
2720 9
                return 'REPEATABLE READ';
2721 9
            case Connection::TRANSACTION_SERIALIZABLE:
2722 9
                return 'SERIALIZABLE';
2723
            default:
2724
                throw new \InvalidArgumentException('Invalid isolation level:' . $level);
2725
        }
2726
    }
2727
2728
    /**
2729
     * @return string
2730
     *
2731
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2732
     */
2733 1
    public function getListDatabasesSQL()
2734
    {
2735 1
        throw DBALException::notSupported(__METHOD__);
2736
    }
2737
2738
    /**
2739
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2740
     *
2741
     * @return string
2742
     *
2743
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2744
     */
2745
    public function getListNamespacesSQL()
2746
    {
2747
        throw DBALException::notSupported(__METHOD__);
2748
    }
2749
2750
    /**
2751
     * @param string $database
2752
     *
2753
     * @return string
2754
     *
2755
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2756
     */
2757
    public function getListSequencesSQL($database)
2758
    {
2759
        throw DBALException::notSupported(__METHOD__);
2760
    }
2761
2762
    /**
2763
     * @param string $table
2764
     *
2765
     * @return string
2766
     *
2767
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2768
     */
2769
    public function getListTableConstraintsSQL($table)
2770
    {
2771
        throw DBALException::notSupported(__METHOD__);
2772
    }
2773
2774
    /**
2775
     * @param string      $table
2776
     * @param string|null $database
2777
     *
2778
     * @return string
2779
     *
2780
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2781
     */
2782
    public function getListTableColumnsSQL($table, $database = null)
2783
    {
2784
        throw DBALException::notSupported(__METHOD__);
2785
    }
2786
2787
    /**
2788
     * @return string
2789
     *
2790
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2791
     */
2792
    public function getListTablesSQL()
2793
    {
2794
        throw DBALException::notSupported(__METHOD__);
2795
    }
2796
2797
    /**
2798
     * @return string
2799
     *
2800
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2801
     */
2802
    public function getListUsersSQL()
2803
    {
2804
        throw DBALException::notSupported(__METHOD__);
2805
    }
2806
2807
    /**
2808
     * Returns the SQL to list all views of a database or user.
2809
     *
2810
     * @param string $database
2811
     *
2812
     * @return string
2813
     *
2814
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2815
     */
2816
    public function getListViewsSQL($database)
2817
    {
2818
        throw DBALException::notSupported(__METHOD__);
2819
    }
2820
2821
    /**
2822
     * Returns the list of indexes for the current database.
2823
     *
2824
     * The current database parameter is optional but will always be passed
2825
     * when using the SchemaManager API and is the database the given table is in.
2826
     *
2827
     * Attention: Some platforms only support currentDatabase when they
2828
     * are connected with that database. Cross-database information schema
2829
     * requests may be impossible.
2830
     *
2831
     * @param string $table
2832
     * @param string $currentDatabase
2833
     *
2834
     * @return string
2835
     *
2836
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2837
     */
2838
    public function getListTableIndexesSQL($table, $currentDatabase = null)
2839
    {
2840
        throw DBALException::notSupported(__METHOD__);
2841
    }
2842
2843
    /**
2844
     * @param string $table
2845
     *
2846
     * @return string
2847
     *
2848
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2849
     */
2850
    public function getListTableForeignKeysSQL($table)
2851
    {
2852
        throw DBALException::notSupported(__METHOD__);
2853
    }
2854
2855
    /**
2856
     * @param string $name
2857
     * @param string $sql
2858
     *
2859
     * @return string
2860
     *
2861
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2862
     */
2863
    public function getCreateViewSQL($name, $sql)
2864
    {
2865
        throw DBALException::notSupported(__METHOD__);
2866
    }
2867
2868
    /**
2869
     * @param string $name
2870
     *
2871
     * @return string
2872
     *
2873
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2874
     */
2875
    public function getDropViewSQL($name)
2876
    {
2877
        throw DBALException::notSupported(__METHOD__);
2878
    }
2879
2880
    /**
2881
     * Returns the SQL snippet to drop an existing sequence.
2882
     *
2883
     * @param Sequence|string $sequence
2884
     *
2885
     * @return string
2886
     *
2887
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2888
     */
2889
    public function getDropSequenceSQL($sequence)
2890
    {
2891
        throw DBALException::notSupported(__METHOD__);
2892
    }
2893
2894
    /**
2895
     * @param string $sequenceName
2896
     *
2897
     * @return string
2898
     *
2899
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2900
     */
2901
    public function getSequenceNextValSQL($sequenceName)
2902
    {
2903
        throw DBALException::notSupported(__METHOD__);
2904
    }
2905
2906
    /**
2907
     * Returns the SQL to create a new database.
2908
     *
2909
     * @param string $database The name of the database that should be created.
2910
     *
2911
     * @return string
2912
     *
2913
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2914
     */
2915 1
    public function getCreateDatabaseSQL($database)
2916
    {
2917 1
        throw DBALException::notSupported(__METHOD__);
2918
    }
2919
2920
    /**
2921
     * Returns the SQL to set the transaction isolation level.
2922
     *
2923
     * @param integer $level
2924
     *
2925
     * @return string
2926
     *
2927
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2928
     */
2929
    public function getSetTransactionIsolationSQL($level)
2930
    {
2931
        throw DBALException::notSupported(__METHOD__);
2932
    }
2933
2934
    /**
2935
     * Obtains DBMS specific SQL to be used to create datetime fields in
2936
     * statements like CREATE TABLE.
2937
     *
2938
     * @param array $fieldDeclaration
2939
     *
2940
     * @return string
2941
     *
2942
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2943
     */
2944
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
2945
    {
2946
        throw DBALException::notSupported(__METHOD__);
2947
    }
2948
2949
    /**
2950
     * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields.
2951
     *
2952
     * @param array $fieldDeclaration
2953
     *
2954
     * @return string
2955
     */
2956 15
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
2957
    {
2958 15
        return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
2959
    }
2960
2961
2962
    /**
2963
     * Obtains DBMS specific SQL to be used to create date fields in statements
2964
     * like CREATE TABLE.
2965
     *
2966
     * @param array $fieldDeclaration
2967
     *
2968
     * @return string
2969
     *
2970
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2971
     */
2972
    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...
2973
    {
2974
        throw DBALException::notSupported(__METHOD__);
2975
    }
2976
2977
    /**
2978
     * Obtains DBMS specific SQL to be used to create time fields in statements
2979
     * like CREATE TABLE.
2980
     *
2981
     * @param array $fieldDeclaration
2982
     *
2983
     * @return string
2984
     *
2985
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2986
     */
2987
    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...
2988
    {
2989
        throw DBALException::notSupported(__METHOD__);
2990
    }
2991
2992
    /**
2993
     * @param array $fieldDeclaration
2994
     *
2995
     * @return string
2996
     */
2997 99
    public function getFloatDeclarationSQL(array $fieldDeclaration)
2998
    {
2999 99
        return 'DOUBLE PRECISION';
3000
    }
3001
3002
    /**
3003
     * Gets the default transaction isolation level of the platform.
3004
     *
3005
     * @return integer The default isolation level.
3006
     *
3007
     * @see Doctrine\DBAL\Connection\TRANSACTION_* constants.
3008
     */
3009
    public function getDefaultTransactionIsolationLevel()
3010
    {
3011
        return Connection::TRANSACTION_READ_COMMITTED;
3012
    }
3013
3014
    /* supports*() methods */
3015
3016
    /**
3017
     * Whether the platform supports sequences.
3018
     *
3019
     * @return boolean
3020
     */
3021 6
    public function supportsSequences()
3022
    {
3023 6
        return false;
3024
    }
3025
3026
    /**
3027
     * Whether the platform supports identity columns.
3028
     *
3029
     * Identity columns are columns that receive an auto-generated value from the
3030
     * database on insert of a row.
3031
     *
3032
     * @return boolean
3033
     */
3034 1
    public function supportsIdentityColumns()
3035
    {
3036 1
        return false;
3037
    }
3038
3039
    /**
3040
     * Whether the platform emulates identity columns through sequences.
3041
     *
3042
     * Some platforms that do not support identity columns natively
3043
     * but support sequences can emulate identity columns by using
3044
     * sequences.
3045
     *
3046
     * @return boolean
3047
     */
3048 12
    public function usesSequenceEmulatedIdentityColumns()
3049
    {
3050 12
        return false;
3051
    }
3052
3053
    /**
3054
     * Returns the name of the sequence for a particular identity column in a particular table.
3055
     *
3056
     * @param string $tableName  The name of the table to return the sequence name for.
3057
     * @param string $columnName The name of the identity column in the table to return the sequence name for.
3058
     *
3059
     * @return string
3060
     *
3061
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3062
     *
3063
     * @see    usesSequenceEmulatedIdentityColumns
3064
     */
3065 11
    public function getIdentitySequenceName($tableName, $columnName)
3066
    {
3067 11
        throw DBALException::notSupported(__METHOD__);
3068
    }
3069
3070
    /**
3071
     * Whether the platform supports indexes.
3072
     *
3073
     * @return boolean
3074
     */
3075 4
    public function supportsIndexes()
3076
    {
3077 4
        return true;
3078
    }
3079
3080
    /**
3081
     * Whether the platform supports partial indexes.
3082
     *
3083
     * @return boolean
3084
     */
3085 126
    public function supportsPartialIndexes()
3086
    {
3087 126
        return false;
3088
    }
3089
3090
    /**
3091
     * Whether the platform supports altering tables.
3092
     *
3093
     * @return boolean
3094
     */
3095 5
    public function supportsAlterTable()
3096
    {
3097 5
        return true;
3098
    }
3099
3100
    /**
3101
     * Whether the platform supports transactions.
3102
     *
3103
     * @return boolean
3104
     */
3105 4
    public function supportsTransactions()
3106
    {
3107 4
        return true;
3108
    }
3109
3110
    /**
3111
     * Whether the platform supports savepoints.
3112
     *
3113
     * @return boolean
3114
     */
3115 20
    public function supportsSavepoints()
3116
    {
3117 20
        return true;
3118
    }
3119
3120
    /**
3121
     * Whether the platform supports releasing savepoints.
3122
     *
3123
     * @return boolean
3124
     */
3125 5
    public function supportsReleaseSavepoints()
3126
    {
3127 5
        return $this->supportsSavepoints();
3128
    }
3129
3130
    /**
3131
     * Whether the platform supports primary key constraints.
3132
     *
3133
     * @return boolean
3134
     */
3135 4
    public function supportsPrimaryConstraints()
3136
    {
3137 4
        return true;
3138
    }
3139
3140
    /**
3141
     * Whether the platform supports foreign key constraints.
3142
     *
3143
     * @return boolean
3144
     */
3145 370
    public function supportsForeignKeyConstraints()
3146
    {
3147 370
        return true;
3148
    }
3149
3150
    /**
3151
     * Whether this platform supports onUpdate in foreign key constraints.
3152
     *
3153
     * @return boolean
3154
     */
3155 89
    public function supportsForeignKeyOnUpdate()
3156
    {
3157 89
        return ($this->supportsForeignKeyConstraints() && true);
3158
    }
3159
3160
    /**
3161
     * Whether the platform supports database schemas.
3162
     *
3163
     * @return boolean
3164
     */
3165 10
    public function supportsSchemas()
3166
    {
3167 10
        return false;
3168
    }
3169
3170
    /**
3171
     * Whether this platform can emulate schemas.
3172
     *
3173
     * Platforms that either support or emulate schemas don't automatically
3174
     * filter a schema for the namespaced elements in {@link
3175
     * AbstractManager#createSchema}.
3176
     *
3177
     * @return boolean
3178
     */
3179 4
    public function canEmulateSchemas()
3180
    {
3181 4
        return false;
3182
    }
3183
3184
    /**
3185
     * Returns the default schema name.
3186
     *
3187
     * @return string
3188
     *
3189
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3190
     */
3191
    public function getDefaultSchemaName()
3192
    {
3193
        throw DBALException::notSupported(__METHOD__);
3194
    }
3195
3196
    /**
3197
     * Whether this platform supports create database.
3198
     *
3199
     * Some databases don't allow to create and drop databases at all or only with certain tools.
3200
     *
3201
     * @return boolean
3202
     */
3203 4
    public function supportsCreateDropDatabase()
3204
    {
3205 4
        return true;
3206
    }
3207
3208
    /**
3209
     * Whether the platform supports getting the affected rows of a recent update/delete type query.
3210
     *
3211
     * @return boolean
3212
     */
3213 4
    public function supportsGettingAffectedRows()
3214
    {
3215 4
        return true;
3216
    }
3217
3218
    /**
3219
     * Whether this platform support to add inline column comments as postfix.
3220
     *
3221
     * @return boolean
3222
     */
3223 161
    public function supportsInlineColumnComments()
3224
    {
3225 161
        return false;
3226
    }
3227
3228
    /**
3229
     * Whether this platform support the proprietary syntax "COMMENT ON asset".
3230
     *
3231
     * @return boolean
3232
     */
3233 229
    public function supportsCommentOnStatement()
3234
    {
3235 229
        return false;
3236
    }
3237
3238
    /**
3239
     * Does this platform have native guid type.
3240
     *
3241
     * @return boolean
3242
     */
3243 249
    public function hasNativeGuidType()
3244
    {
3245 249
        return false;
3246
    }
3247
3248
    /**
3249
     * Does this platform have native JSON type.
3250
     *
3251
     * @return boolean
3252
     */
3253 616
    public function hasNativeJsonType()
3254
    {
3255 616
        return false;
3256
    }
3257
3258
    /**
3259
     * @deprecated
3260
     * @todo Remove in 3.0
3261
     */
3262
    public function getIdentityColumnNullInsertSQL()
3263
    {
3264
        return "";
3265
    }
3266
3267
    /**
3268
     * Whether this platform supports views.
3269
     *
3270
     * @return boolean
3271
     */
3272 1
    public function supportsViews()
3273
    {
3274 1
        return true;
3275
    }
3276
3277
    /**
3278
     * Does this platform support column collation?
3279
     *
3280
     * @return boolean
3281
     */
3282
    public function supportsColumnCollation()
3283
    {
3284
        return false;
3285
    }
3286
3287
    /**
3288
     * Gets the format string, as accepted by the date() function, that describes
3289
     * the format of a stored datetime value of this platform.
3290
     *
3291
     * @return string The format string.
3292
     */
3293 17
    public function getDateTimeFormatString()
3294
    {
3295 17
        return 'Y-m-d H:i:s';
3296
    }
3297
3298
    /**
3299
     * Gets the format string, as accepted by the date() function, that describes
3300
     * the format of a stored datetime with timezone value of this platform.
3301
     *
3302
     * @return string The format string.
3303
     */
3304 7
    public function getDateTimeTzFormatString()
3305
    {
3306 7
        return 'Y-m-d H:i:s';
3307
    }
3308
3309
    /**
3310
     * Gets the format string, as accepted by the date() function, that describes
3311
     * the format of a stored date value of this platform.
3312
     *
3313
     * @return string The format string.
3314
     */
3315 6
    public function getDateFormatString()
3316
    {
3317 6
        return 'Y-m-d';
3318
    }
3319
3320
    /**
3321
     * Gets the format string, as accepted by the date() function, that describes
3322
     * the format of a stored time value of this platform.
3323
     *
3324
     * @return string The format string.
3325
     */
3326 5
    public function getTimeFormatString()
3327
    {
3328 5
        return 'H:i:s';
3329
    }
3330
3331
    /**
3332
     * Adds an driver-specific LIMIT clause to the query.
3333
     *
3334
     * @param string       $query
3335
     * @param integer|null $limit
3336
     * @param integer|null $offset
3337
     *
3338
     * @return string
3339
     *
3340
     * @throws DBALException
3341
     */
3342 113
    final public function modifyLimitQuery($query, $limit, $offset = null)
3343
    {
3344 113
        if ($limit !== null) {
3345 108
            $limit = (int) $limit;
3346
        }
3347
3348 113
        if ($offset !== null) {
3349 44
            $offset = (int) $offset;
3350
3351 44
            if ($offset < 0) {
3352
                throw new DBALException("LIMIT argument offset=$offset is not valid");
3353
            }
3354 44
            if ($offset > 0 && ! $this->supportsLimitOffset()) {
3355
                throw new DBALException(sprintf("Platform %s does not support offset values in limit queries.", $this->getName()));
3356
            }
3357
        }
3358
3359 113
        return $this->doModifyLimitQuery($query, $limit, $offset);
3360
    }
3361
3362
    /**
3363
     * Adds an driver-specific LIMIT clause to the query.
3364
     *
3365
     * @param string       $query
3366
     * @param integer|null $limit
3367
     * @param integer|null $offset
3368
     *
3369
     * @return string
3370
     */
3371 17
    protected function doModifyLimitQuery($query, $limit, $offset)
3372
    {
3373 17
        if ($limit !== null) {
3374 17
            $query .= ' LIMIT ' . $limit;
3375
        }
3376
3377 17
        if ($offset !== null) {
3378 12
            $query .= ' OFFSET ' . $offset;
3379
        }
3380
3381 17
        return $query;
3382
    }
3383
3384
    /**
3385
     * Whether the database platform support offsets in modify limit clauses.
3386
     *
3387
     * @return boolean
3388
     */
3389 17
    public function supportsLimitOffset()
3390
    {
3391 17
        return true;
3392
    }
3393
3394
    /**
3395
     * Gets the character casing of a column in an SQL result set of this platform.
3396
     *
3397
     * @param string $column The column name for which to get the correct character casing.
3398
     *
3399
     * @return string The column name in the character casing used in SQL result sets.
3400
     */
3401
    public function getSQLResultCasing($column)
3402
    {
3403
        return $column;
3404
    }
3405
3406
    /**
3407
     * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
3408
     * by restrictions of the platform, like a maximum length.
3409
     *
3410
     * @param string $schemaElementName
3411
     *
3412
     * @return string
3413
     */
3414
    public function fixSchemaElementName($schemaElementName)
3415
    {
3416
        return $schemaElementName;
3417
    }
3418
3419
    /**
3420
     * Maximum length of any given database identifier, like tables or column names.
3421
     *
3422
     * @return integer
3423
     */
3424 13
    public function getMaxIdentifierLength()
3425
    {
3426 13
        return 63;
3427
    }
3428
3429
    /**
3430
     * Returns the insert SQL for an empty insert statement.
3431
     *
3432
     * @param string $tableName
3433
     * @param string $identifierColumnName
3434
     *
3435
     * @return string
3436
     */
3437 1
    public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
3438
    {
3439 1
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
3440
    }
3441
3442
    /**
3443
     * Generates a Truncate Table SQL statement for a given table.
3444
     *
3445
     * Cascade is not supported on many platforms but would optionally cascade the truncate by
3446
     * following the foreign keys.
3447
     *
3448
     * @param string  $tableName
3449
     * @param boolean $cascade
3450
     *
3451
     * @return string
3452
     */
3453 2
    public function getTruncateTableSQL($tableName, $cascade = false)
3454
    {
3455 2
        $tableIdentifier = new Identifier($tableName);
3456
3457 2
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3458
    }
3459
3460
    /**
3461
     * This is for test reasons, many vendors have special requirements for dummy statements.
3462
     *
3463
     * @return string
3464
     */
3465 6
    public function getDummySelectSQL()
3466
    {
3467 6
        return 'SELECT 1';
3468
    }
3469
3470
    /**
3471
     * Returns the SQL to create a new savepoint.
3472
     *
3473
     * @param string $savepoint
3474
     *
3475
     * @return string
3476
     */
3477 1
    public function createSavePoint($savepoint)
3478
    {
3479 1
        return 'SAVEPOINT ' . $savepoint;
3480
    }
3481
3482
    /**
3483
     * Returns the SQL to release a savepoint.
3484
     *
3485
     * @param string $savepoint
3486
     *
3487
     * @return string
3488
     */
3489 1
    public function releaseSavePoint($savepoint)
3490
    {
3491 1
        return 'RELEASE SAVEPOINT ' . $savepoint;
3492
    }
3493
3494
    /**
3495
     * Returns the SQL to rollback a savepoint.
3496
     *
3497
     * @param string $savepoint
3498
     *
3499
     * @return string
3500
     */
3501 1
    public function rollbackSavePoint($savepoint)
3502
    {
3503 1
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3504
    }
3505
3506
    /**
3507
     * Returns the keyword list instance of this platform.
3508
     *
3509
     * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList
3510
     *
3511
     * @throws \Doctrine\DBAL\DBALException If no keyword list is specified.
3512
     */
3513 962
    final public function getReservedKeywordsList()
3514
    {
3515
        // Check for an existing instantiation of the keywords class.
3516 962
        if ($this->_keywords) {
3517 901
            return $this->_keywords;
3518
        }
3519
3520 841
        $class = $this->getReservedKeywordsClass();
3521 841
        $keywords = new $class;
3522 841
        if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) {
3523
            throw DBALException::notSupported(__METHOD__);
3524
        }
3525
3526
        // Store the instance so it doesn't need to be generated on every request.
3527 841
        $this->_keywords = $keywords;
3528
3529 841
        return $keywords;
3530
    }
3531
3532
    /**
3533
     * Returns the class name of the reserved keywords list.
3534
     *
3535
     * @return string
3536
     *
3537
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3538
     */
3539
    protected function getReservedKeywordsClass()
3540
    {
3541
        throw DBALException::notSupported(__METHOD__);
3542
    }
3543
3544
    /**
3545
     * Quotes a literal string.
3546
     * This method is NOT meant to fix SQL injections!
3547
     * It is only meant to escape this platform's string literal
3548
     * quote character inside the given literal string.
3549
     *
3550
     * @param string $str The literal string to be quoted.
3551
     *
3552
     * @return string The quoted literal string.
3553
     */
3554 293
    public function quoteStringLiteral($str)
3555
    {
3556 293
        $c = $this->getStringLiteralQuoteCharacter();
3557
3558 293
        return $c . str_replace($c, $c . $c, $str) . $c;
3559
    }
3560
3561
    /**
3562
     * Gets the character used for string literal quoting.
3563
     *
3564
     * @return string
3565
     */
3566 309
    public function getStringLiteralQuoteCharacter()
3567
    {
3568 309
        return "'";
3569
    }
3570
}
3571