Completed
Pull Request — master (#2835)
by Grégoire
04:14
created

AbstractPlatform   F

Complexity

Total Complexity 385

Size/Duplication

Total Lines 3506
Duplicated Lines 6.67 %

Coupling/Cohesion

Components 6
Dependencies 18

Test Coverage

Coverage 76.9%

Importance

Changes 0
Metric Value
wmc 385
lcom 6
cbo 18
dl 234
loc 3506
ccs 616
cts 801
cp 0.769
rs 0.6314
c 0
b 0
f 0

214 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A setEventManager() 0 4 1
A getEventManager() 0 4 1
getBooleanTypeDeclarationSQL() 0 1 ?
getIntegerTypeDeclarationSQL() 0 1 ?
getBigIntTypeDeclarationSQL() 0 1 ?
getSmallIntTypeDeclarationSQL() 0 1 ?
_getCommonIntegerTypeDeclarationSQL() 0 1 ?
initializeDoctrineTypeMappings() 0 1 ?
A initializeAllDoctrineTypeMappings() 0 10 3
A getVarcharTypeDeclarationSQL() 0 14 4
A getBinaryTypeDeclarationSQL() 0 14 4
A getGuidTypeDeclarationSQL() 0 7 1
A getJsonTypeDeclarationSQL() 0 4 1
A getVarcharTypeDeclarationSQLSnippet() 0 4 1
A getBinaryTypeDeclarationSQLSnippet() 0 4 1
getClobTypeDeclarationSQL() 0 1 ?
getBlobTypeDeclarationSQL() 0 1 ?
getName() 0 1 ?
A registerDoctrineTypeMapping() 0 19 4
A getDoctrineTypeMapping() 0 14 3
A hasDoctrineTypeMappingFor() 0 10 2
A initializeCommentedDoctrineTypes() 0 12 3
A isCommentedDoctrineType() 0 8 2
A markDoctrineTypeCommented() 0 8 3
A getDoctrineTypeComment() 0 4 1
A getColumnComment() 0 10 2
A getIdentifierQuoteCharacter() 0 4 1
A getSqlCommentStartString() 0 4 1
A getSqlCommentEndString() 0 4 1
A getVarcharMaxLength() 0 4 1
A getVarcharDefaultLength() 0 4 1
A getBinaryMaxLength() 0 4 1
A getBinaryDefaultLength() 0 4 1
A getWildcards() 0 4 1
A getRegexpExpression() 0 4 1
A getGuidExpression() 0 4 1
A getAvgExpression() 0 4 1
A getCountExpression() 0 4 1
A getMaxExpression() 0 4 1
A getMinExpression() 0 4 1
A getSumExpression() 0 4 1
A getMd5Expression() 0 4 1
A getLengthExpression() 0 4 1
A getSqrtExpression() 0 4 1
A getRoundExpression() 0 4 1
A getModExpression() 0 4 1
C getTrimExpression() 0 28 7
A getRtrimExpression() 0 4 1
A getLtrimExpression() 0 4 1
A getUpperExpression() 0 4 1
A getLowerExpression() 0 4 1
A getLocateExpression() 0 4 1
A getNowExpression() 0 4 1
A getSubstringExpression() 8 8 2
A getConcatExpression() 0 4 1
A getNotExpression() 0 4 1
A getIsNullExpression() 0 4 1
A getIsNotNullExpression() 0 4 1
A getBetweenExpression() 0 4 1
A getAcosExpression() 0 4 1
A getSinExpression() 0 4 1
A getPiExpression() 0 4 1
A getCosExpression() 0 4 1
A getDateDiffExpression() 0 4 1
A getDateAddSecondsExpression() 0 4 1
A getDateSubSecondsExpression() 0 4 1
A getDateAddMinutesExpression() 0 4 1
A getDateSubMinutesExpression() 0 4 1
A getDateAddHourExpression() 0 4 1
A getDateSubHourExpression() 0 4 1
A getDateAddDaysExpression() 0 4 1
A getDateSubDaysExpression() 0 4 1
A getDateAddWeeksExpression() 0 4 1
A getDateSubWeeksExpression() 0 4 1
A getDateAddMonthExpression() 0 4 1
A getDateSubMonthExpression() 0 4 1
A getDateAddQuartersExpression() 0 4 1
A getDateSubQuartersExpression() 0 4 1
A getDateAddYearsExpression() 0 4 1
A getDateSubYearsExpression() 0 4 1
A getDateArithmeticIntervalExpression() 0 4 1
A getBitAndComparisonExpression() 0 4 1
A getBitOrComparisonExpression() 0 4 1
A getForUpdateSQL() 0 4 1
A appendLockHint() 0 4 1
A getReadLockSQL() 0 4 1
A getWriteLockSQL() 0 4 1
A getDropDatabaseSQL() 0 4 1
B getDropTableSQL() 0 21 6
A getDropTemporaryTableSQL() 0 4 1
A getDropIndexSQL() 10 10 3
A getDropConstraintSQL() 15 15 3
A getDropForeignKeySQL() 15 15 3
F getCreateTableSQL() 21 90 23
A getCommentOnColumnSQL() 9 9 1
A getInlineColumnCommentSQL() 0 8 2
C _getCreateTableSQL() 8 38 12
A getCreateTemporaryTableSnippetSQL() 0 4 1
A getCreateSequenceSQL() 0 4 1
A getAlterSequenceSQL() 0 4 1
A getCreateIndexSQL() 0 21 4
A getPartialIndexSQL() 0 8 3
A getCreateIndexSQLFlags() 0 4 2
A getCreatePrimaryKeySQL() 0 4 1
A getCreateSchemaSQL() 0 4 1
A quoteIdentifier() 0 10 2
A quoteSingleIdentifier() 0 6 1
A getCreateForeignKeySQL() 0 10 2
A getAlterTableSQL() 0 4 1
A onSchemaAlterTableAddColumn() 17 17 3
A onSchemaAlterTableRemoveColumn() 17 17 3
A onSchemaAlterTableChangeColumn() 17 17 3
A onSchemaAlterTableRenameColumn() 17 17 3
A onSchemaAlterTable() 17 17 3
B getPreAlterTableIndexForeignKeySQL() 8 23 6
C getPostAlterTableIndexForeignKeySQL() 9 36 8
A getRenameIndexSQL() 0 7 1
A _getAlterTableIndexForeignKeySQL() 0 4 1
A getColumnDeclarationListSQL() 0 10 2
F getColumnDeclarationSQL() 0 31 15
B getDecimalTypeDeclarationSQL() 0 9 5
B getCreateConstraintSQL() 0 31 6
C getDefaultValueDeclarationSQL() 0 28 15
B getCheckDeclarationSQL() 6 19 5
A getUniqueConstraintDeclarationSQL() 13 13 2
A getIndexDeclarationSQL() 13 13 2
A getCustomTypeDeclarationSQL() 0 4 1
A getIndexFieldDeclarationListSQL() 0 14 3
A getTemporaryTableSQL() 0 4 1
A getTemporaryTableName() 0 4 1
A getForeignKeyDeclarationSQL() 0 7 1
A getAdvancedForeignKeyOptionsSQL() 0 12 4
B getForeignKeyReferentialActionSQL() 14 14 6
B getForeignKeyBaseDeclarationSQL() 0 25 5
A getUniqueFieldDeclarationSQL() 0 4 1
A getColumnCharsetDeclarationSQL() 0 4 1
A getColumnCollationDeclarationSQL() 0 4 2
A prefersSequences() 0 4 1
A prefersIdentityColumns() 0 4 1
B convertBooleans() 0 14 5
A convertFromBoolean() 0 4 2
A convertBooleansToDatabaseValue() 0 4 1
A getCurrentDateSQL() 0 4 1
A getCurrentTimeSQL() 0 4 1
A getCurrentTimestampSQL() 0 4 1
B _getTransactionIsolationLevelSQL() 0 15 5
A getListDatabasesSQL() 0 4 1
A getListNamespacesSQL() 0 4 1
A getListSequencesSQL() 0 4 1
A getListTableConstraintsSQL() 0 4 1
A getListTableColumnsSQL() 0 4 1
A getListTablesSQL() 0 4 1
A getListUsersSQL() 0 4 1
A getListViewsSQL() 0 4 1
A getListTableIndexesSQL() 0 4 1
A getListTableForeignKeysSQL() 0 4 1
A getCreateViewSQL() 0 4 1
A getDropViewSQL() 0 4 1
A getDropSequenceSQL() 0 4 1
A getSequenceNextValSQL() 0 4 1
A getCreateDatabaseSQL() 0 4 1
A getSetTransactionIsolationSQL() 0 4 1
A getDateTimeTypeDeclarationSQL() 0 4 1
A getDateTimeTzTypeDeclarationSQL() 0 4 1
A getDateTypeDeclarationSQL() 0 4 1
A getTimeTypeDeclarationSQL() 0 4 1
A getFloatDeclarationSQL() 0 4 1
A getDefaultTransactionIsolationLevel() 0 4 1
A supportsSequences() 0 4 1
A supportsIdentityColumns() 0 4 1
A usesSequenceEmulatedIdentityColumns() 0 4 1
A getIdentitySequenceName() 0 4 1
A supportsIndexes() 0 4 1
A supportsPartialIndexes() 0 4 1
A supportsAlterTable() 0 4 1
A supportsTransactions() 0 4 1
A supportsSavepoints() 0 4 1
A supportsReleaseSavepoints() 0 4 1
A supportsPrimaryConstraints() 0 4 1
A supportsForeignKeyConstraints() 0 4 1
A supportsForeignKeyOnUpdate() 0 4 2
A supportsSchemas() 0 4 1
A canEmulateSchemas() 0 4 1
A getDefaultSchemaName() 0 4 1
A supportsCreateDropDatabase() 0 4 1
A supportsGettingAffectedRows() 0 4 1
A supportsInlineColumnComments() 0 4 1
A supportsCommentOnStatement() 0 4 1
A hasNativeGuidType() 0 4 1
A hasNativeJsonType() 0 4 1
A getIdentityColumnNullInsertSQL() 0 4 1
A supportsViews() 0 4 1
A supportsColumnCollation() 0 4 1
A getDateTimeFormatString() 0 4 1
A getDateTimeTzFormatString() 0 4 1
A getDateFormatString() 0 4 1
A getTimeFormatString() 0 4 1
B modifyLimitQuery() 0 19 6
A doModifyLimitQuery() 0 12 3
A supportsLimitOffset() 0 4 1
A getSQLResultCasing() 0 4 1
A fixSchemaElementName() 0 4 1
A getMaxIdentifierLength() 0 4 1
A getEmptyIdentityInsertSQL() 0 4 1
A getTruncateTableSQL() 0 6 1
A getDummySelectSQL() 0 4 1
A createSavePoint() 0 4 1
A releaseSavePoint() 0 4 1
A rollbackSavePoint() 0 4 1
A getReservedKeywordsList() 0 18 3
A getReservedKeywordsClass() 0 4 1
A quoteStringLiteral() 0 6 1
A getStringLiteralQuoteCharacter() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractPlatform often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractPlatform, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Platforms;
21
22
use Doctrine\Common\EventManager;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\DBALException;
25
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
26
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
27
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
28
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
29
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
30
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
31
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
32
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
33
use Doctrine\DBAL\Events;
34
use Doctrine\DBAL\Schema\Column;
35
use Doctrine\DBAL\Schema\ColumnDiff;
36
use Doctrine\DBAL\Schema\Constraint;
37
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
38
use Doctrine\DBAL\Schema\Identifier;
39
use Doctrine\DBAL\Schema\Index;
40
use Doctrine\DBAL\Schema\Sequence;
41
use Doctrine\DBAL\Schema\Table;
42
use Doctrine\DBAL\Schema\TableDiff;
43
use Doctrine\DBAL\Types;
44
use Doctrine\DBAL\Types\Type;
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 3000
    public function __construct()
161
    {
162 3000
    }
163
164
    /**
165
     * Sets the EventManager used by the Platform.
166
     *
167
     * @param \Doctrine\Common\EventManager $eventManager
168
     */
169 76
    public function setEventManager(EventManager $eventManager)
170
    {
171 76
        $this->_eventManager = $eventManager;
172 76
    }
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 = [];
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
     * Gets all SQL wildcard characters of the platform.
605
     *
606
     * @return array
607
     */
608
    public function getWildcards()
609
    {
610
        return ['%', '_'];
611
    }
612
613
    /**
614
     * Returns the regular expression operator.
615
     *
616
     * @return string
617
     *
618
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
619
     */
620 5
    public function getRegexpExpression()
621
    {
622 5
        throw DBALException::notSupported(__METHOD__);
623
    }
624
625
    /**
626
     * Returns the global unique identifier expression.
627
     *
628
     * @return string
629
     *
630
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
631
     */
632
    public function getGuidExpression()
633
    {
634
        throw DBALException::notSupported(__METHOD__);
635
    }
636
637
    /**
638
     * Returns the SQL snippet to get the average value of a column.
639
     *
640
     * @param string $column The column to use.
641
     *
642
     * @return string Generated SQL including an AVG aggregate function.
643
     */
644
    public function getAvgExpression($column)
645
    {
646
        return 'AVG(' . $column . ')';
647
    }
648
649
    /**
650
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
651
     *
652
     * If a '*' is used instead of a column the number of selected rows is returned.
653
     *
654
     * @param string|integer $column The column to use.
655
     *
656
     * @return string Generated SQL including a COUNT aggregate function.
657
     */
658
    public function getCountExpression($column)
659
    {
660
        return 'COUNT(' . $column . ')';
661
    }
662
663
    /**
664
     * Returns the SQL snippet to get the highest value of a column.
665
     *
666
     * @param string $column The column to use.
667
     *
668
     * @return string Generated SQL including a MAX aggregate function.
669
     */
670
    public function getMaxExpression($column)
671
    {
672
        return 'MAX(' . $column . ')';
673
    }
674
675
    /**
676
     * Returns the SQL snippet to get the lowest value of a column.
677
     *
678
     * @param string $column The column to use.
679
     *
680
     * @return string Generated SQL including a MIN aggregate function.
681
     */
682
    public function getMinExpression($column)
683
    {
684
        return 'MIN(' . $column . ')';
685
    }
686
687
    /**
688
     * Returns the SQL snippet to get the total sum of a column.
689
     *
690
     * @param string $column The column to use.
691
     *
692
     * @return string Generated SQL including a SUM aggregate function.
693
     */
694
    public function getSumExpression($column)
695
    {
696
        return 'SUM(' . $column . ')';
697
    }
698
699
    // scalar functions
700
701
    /**
702
     * Returns the SQL snippet to get the md5 sum of a field.
703
     *
704
     * Note: Not SQL92, but common functionality.
705
     *
706
     * @param string $column
707
     *
708
     * @return string
709
     */
710
    public function getMd5Expression($column)
711
    {
712
        return 'MD5(' . $column . ')';
713
    }
714
715
    /**
716
     * Returns the SQL snippet to get the length of a text field.
717
     *
718
     * @param string $column
719
     *
720
     * @return string
721
     */
722
    public function getLengthExpression($column)
723
    {
724
        return 'LENGTH(' . $column . ')';
725
    }
726
727
    /**
728
     * Returns the SQL snippet to get the squared value of a column.
729
     *
730
     * @param string $column The column to use.
731
     *
732
     * @return string Generated SQL including an SQRT aggregate function.
733
     */
734
    public function getSqrtExpression($column)
735
    {
736
        return 'SQRT(' . $column . ')';
737
    }
738
739
    /**
740
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
741
     *
742
     * @param string  $column
743
     * @param integer $decimals
744
     *
745
     * @return string
746
     */
747
    public function getRoundExpression($column, $decimals = 0)
748
    {
749
        return 'ROUND(' . $column . ', ' . $decimals . ')';
750
    }
751
752
    /**
753
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
754
     *
755
     * @param string $expression1
756
     * @param string $expression2
757
     *
758
     * @return string
759
     */
760
    public function getModExpression($expression1, $expression2)
761
    {
762
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
763
    }
764
765
    /**
766
     * Returns the SQL snippet to trim a string.
767
     *
768
     * @param string         $str  The expression to apply the trim to.
769
     * @param integer        $pos  The position of the trim (leading/trailing/both).
770
     * @param string|boolean $char The char to trim, has to be quoted already. Defaults to space.
771
     *
772
     * @return string
773
     */
774
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
775
    {
776
        $expression = '';
777
778
        switch ($pos) {
779
            case self::TRIM_LEADING:
780
                $expression = 'LEADING ';
781
                break;
782
783
            case self::TRIM_TRAILING:
784
                $expression = 'TRAILING ';
785
                break;
786
787
            case self::TRIM_BOTH:
788
                $expression = 'BOTH ';
789
                break;
790
        }
791
792
        if (false !== $char) {
793
            $expression .= $char . ' ';
794
        }
795
796
        if ($pos || false !== $char) {
797
            $expression .= 'FROM ';
798
        }
799
800
        return 'TRIM(' . $expression . $str . ')';
801
    }
802
803
    /**
804
     * Returns the SQL snippet to trim trailing space characters from the expression.
805
     *
806
     * @param string $str Literal string or column name.
807
     *
808
     * @return string
809
     */
810 4
    public function getRtrimExpression($str)
811
    {
812 4
        return 'RTRIM(' . $str . ')';
813
    }
814
815
    /**
816
     * Returns the SQL snippet to trim leading space characters from the expression.
817
     *
818
     * @param string $str Literal string or column name.
819
     *
820
     * @return string
821
     */
822 4
    public function getLtrimExpression($str)
823
    {
824 4
        return 'LTRIM(' . $str . ')';
825
    }
826
827
    /**
828
     * Returns the SQL snippet to change all characters from the expression to uppercase,
829
     * according to the current character set mapping.
830
     *
831
     * @param string $str Literal string or column name.
832
     *
833
     * @return string
834
     */
835
    public function getUpperExpression($str)
836
    {
837
        return 'UPPER(' . $str . ')';
838
    }
839
840
    /**
841
     * Returns the SQL snippet to change all characters from the expression to lowercase,
842
     * according to the current character set mapping.
843
     *
844
     * @param string $str Literal string or column name.
845
     *
846
     * @return string
847
     */
848
    public function getLowerExpression($str)
849
    {
850
        return 'LOWER(' . $str . ')';
851
    }
852
853
    /**
854
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
855
     *
856
     * @param string          $str      Literal string.
857
     * @param string          $substr   Literal string to find.
858
     * @param integer|boolean $startPos Position to start at, beginning of string by default.
859
     *
860
     * @return string
861
     *
862
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
863
     */
864
    public function getLocateExpression($str, $substr, $startPos = false)
865
    {
866
        throw DBALException::notSupported(__METHOD__);
867
    }
868
869
    /**
870
     * Returns the SQL snippet to get the current system date.
871
     *
872
     * @return string
873
     */
874
    public function getNowExpression()
875
    {
876
        return 'NOW()';
877
    }
878
879
    /**
880
     * Returns a SQL snippet to get a substring inside an SQL statement.
881
     *
882
     * Note: Not SQL92, but common functionality.
883
     *
884
     * SQLite only supports the 2 parameter variant of this function.
885
     *
886
     * @param string       $value  An sql string literal or column name/alias.
887
     * @param integer      $from   Where to start the substring portion.
888
     * @param integer|null $length The substring portion length.
889
     *
890
     * @return string
891
     */
892 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...
893
    {
894
        if ($length === null) {
895
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
896
        }
897
898
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
899
    }
900
901
    /**
902
     * Returns a SQL snippet to concatenate the given expressions.
903
     *
904
     * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
905
     *
906
     * @return string
907
     */
908 5
    public function getConcatExpression()
909
    {
910 5
        return join(' || ', func_get_args());
911
    }
912
913
    /**
914
     * Returns the SQL for a logical not.
915
     *
916
     * Example:
917
     * <code>
918
     * $q = new Doctrine_Query();
919
     * $e = $q->expr;
920
     * $q->select('*')->from('table')
921
     *   ->where($e->eq('id', $e->not('null'));
922
     * </code>
923
     *
924
     * @param string $expression
925
     *
926
     * @return string The logical expression.
927
     */
928
    public function getNotExpression($expression)
929
    {
930
        return 'NOT(' . $expression . ')';
931
    }
932
933
    /**
934
     * Returns the SQL that checks if an expression is null.
935
     *
936
     * @param string $expression The expression that should be compared to null.
937
     *
938
     * @return string The logical expression.
939
     */
940 4
    public function getIsNullExpression($expression)
941
    {
942 4
        return $expression . ' IS NULL';
943
    }
944
945
    /**
946
     * Returns the SQL that checks if an expression is not null.
947
     *
948
     * @param string $expression The expression that should be compared to null.
949
     *
950
     * @return string The logical expression.
951
     */
952
    public function getIsNotNullExpression($expression)
953
    {
954
        return $expression . ' IS NOT NULL';
955
    }
956
957
    /**
958
     * Returns the SQL that checks if an expression evaluates to a value between two values.
959
     *
960
     * The parameter $expression is checked if it is between $value1 and $value2.
961
     *
962
     * Note: There is a slight difference in the way BETWEEN works on some databases.
963
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
964
     * independence you should avoid using between().
965
     *
966
     * @param string $expression The value to compare to.
967
     * @param string $value1     The lower value to compare with.
968
     * @param string $value2     The higher value to compare with.
969
     *
970
     * @return string The logical expression.
971
     */
972
    public function getBetweenExpression($expression, $value1, $value2)
973
    {
974
        return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
975
    }
976
977
    /**
978
     * Returns the SQL to get the arccosine of a value.
979
     *
980
     * @param string $value
981
     *
982
     * @return string
983
     */
984
    public function getAcosExpression($value)
985
    {
986
        return 'ACOS(' . $value . ')';
987
    }
988
989
    /**
990
     * Returns the SQL to get the sine of a value.
991
     *
992
     * @param string $value
993
     *
994
     * @return string
995
     */
996
    public function getSinExpression($value)
997
    {
998
        return 'SIN(' . $value . ')';
999
    }
1000
1001
    /**
1002
     * Returns the SQL to get the PI value.
1003
     *
1004
     * @return string
1005
     */
1006
    public function getPiExpression()
1007
    {
1008
        return 'PI()';
1009
    }
1010
1011
    /**
1012
     * Returns the SQL to get the cosine of a value.
1013
     *
1014
     * @param string $value
1015
     *
1016
     * @return string
1017
     */
1018
    public function getCosExpression($value)
1019
    {
1020
        return 'COS(' . $value . ')';
1021
    }
1022
1023
    /**
1024
     * Returns the SQL to calculate the difference in days between the two passed dates.
1025
     *
1026
     * Computes diff = date1 - date2.
1027
     *
1028
     * @param string $date1
1029
     * @param string $date2
1030
     *
1031
     * @return string
1032
     *
1033
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1034
     */
1035
    public function getDateDiffExpression($date1, $date2)
1036
    {
1037
        throw DBALException::notSupported(__METHOD__);
1038
    }
1039
1040
    /**
1041
     * Returns the SQL to add the number of given seconds to a date.
1042
     *
1043
     * @param string  $date
1044
     * @param integer $seconds
1045
     *
1046
     * @return string
1047
     *
1048
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1049
     */
1050 6
    public function getDateAddSecondsExpression($date, $seconds)
1051
    {
1052 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1053
    }
1054
1055
    /**
1056
     * Returns the SQL to subtract the number of given seconds from a date.
1057
     *
1058
     * @param string  $date
1059
     * @param integer $seconds
1060
     *
1061
     * @return string
1062
     *
1063
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1064
     */
1065 6
    public function getDateSubSecondsExpression($date, $seconds)
1066
    {
1067 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1068
    }
1069
1070
    /**
1071
     * Returns the SQL to add the number of given minutes to a date.
1072
     *
1073
     * @param string  $date
1074
     * @param integer $minutes
1075
     *
1076
     * @return string
1077
     *
1078
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1079
     */
1080 6
    public function getDateAddMinutesExpression($date, $minutes)
1081
    {
1082 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1083
    }
1084
1085
    /**
1086
     * Returns the SQL to subtract the number of given minutes from a date.
1087
     *
1088
     * @param string  $date
1089
     * @param integer $minutes
1090
     *
1091
     * @return string
1092
     *
1093
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1094
     */
1095 6
    public function getDateSubMinutesExpression($date, $minutes)
1096
    {
1097 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1098
    }
1099
1100
    /**
1101
     * Returns the SQL to add the number of given hours to a date.
1102
     *
1103
     * @param string  $date
1104
     * @param integer $hours
1105
     *
1106
     * @return string
1107
     *
1108
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1109
     */
1110 6
    public function getDateAddHourExpression($date, $hours)
1111
    {
1112 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1113
    }
1114
1115
    /**
1116
     * Returns the SQL to subtract the number of given hours to a date.
1117
     *
1118
     * @param string  $date
1119
     * @param integer $hours
1120
     *
1121
     * @return string
1122
     *
1123
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1124
     */
1125 6
    public function getDateSubHourExpression($date, $hours)
1126
    {
1127 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1128
    }
1129
1130
    /**
1131
     * Returns the SQL to add the number of given days to a date.
1132
     *
1133
     * @param string  $date
1134
     * @param integer $days
1135
     *
1136
     * @return string
1137
     *
1138
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1139
     */
1140 6
    public function getDateAddDaysExpression($date, $days)
1141
    {
1142 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, self::DATE_INTERVAL_UNIT_DAY);
1143
    }
1144
1145
    /**
1146
     * Returns the SQL to subtract the number of given days to a date.
1147
     *
1148
     * @param string  $date
1149
     * @param integer $days
1150
     *
1151
     * @return string
1152
     *
1153
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1154
     */
1155 6
    public function getDateSubDaysExpression($date, $days)
1156
    {
1157 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, self::DATE_INTERVAL_UNIT_DAY);
1158
    }
1159
1160
    /**
1161
     * Returns the SQL to add the number of given weeks to a date.
1162
     *
1163
     * @param string  $date
1164
     * @param integer $weeks
1165
     *
1166
     * @return string
1167
     *
1168
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1169
     */
1170 6
    public function getDateAddWeeksExpression($date, $weeks)
1171
    {
1172 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1173
    }
1174
1175
    /**
1176
     * Returns the SQL to subtract the number of given weeks from a date.
1177
     *
1178
     * @param string  $date
1179
     * @param integer $weeks
1180
     *
1181
     * @return string
1182
     *
1183
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1184
     */
1185 6
    public function getDateSubWeeksExpression($date, $weeks)
1186
    {
1187 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1188
    }
1189
1190
    /**
1191
     * Returns the SQL to add the number of given months to a date.
1192
     *
1193
     * @param string  $date
1194
     * @param integer $months
1195
     *
1196
     * @return string
1197
     *
1198
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1199
     */
1200 6
    public function getDateAddMonthExpression($date, $months)
1201
    {
1202 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, self::DATE_INTERVAL_UNIT_MONTH);
1203
    }
1204
1205
    /**
1206
     * Returns the SQL to subtract the number of given months to a date.
1207
     *
1208
     * @param string  $date
1209
     * @param integer $months
1210
     *
1211
     * @return string
1212
     *
1213
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1214
     */
1215 6
    public function getDateSubMonthExpression($date, $months)
1216
    {
1217 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, self::DATE_INTERVAL_UNIT_MONTH);
1218
    }
1219
1220
    /**
1221
     * Returns the SQL to add the number of given quarters to a date.
1222
     *
1223
     * @param string  $date
1224
     * @param integer $quarters
1225
     *
1226
     * @return string
1227
     *
1228
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1229
     */
1230 6
    public function getDateAddQuartersExpression($date, $quarters)
1231
    {
1232 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1233
    }
1234
1235
    /**
1236
     * Returns the SQL to subtract the number of given quarters from a date.
1237
     *
1238
     * @param string  $date
1239
     * @param integer $quarters
1240
     *
1241
     * @return string
1242
     *
1243
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1244
     */
1245 6
    public function getDateSubQuartersExpression($date, $quarters)
1246
    {
1247 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1248
    }
1249
1250
    /**
1251
     * Returns the SQL to add the number of given years to a date.
1252
     *
1253
     * @param string  $date
1254
     * @param integer $years
1255
     *
1256
     * @return string
1257
     *
1258
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1259
     */
1260 6
    public function getDateAddYearsExpression($date, $years)
1261
    {
1262 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, self::DATE_INTERVAL_UNIT_YEAR);
1263
    }
1264
1265
    /**
1266
     * Returns the SQL to subtract the number of given years from a date.
1267
     *
1268
     * @param string  $date
1269
     * @param integer $years
1270
     *
1271
     * @return string
1272
     *
1273
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1274
     */
1275 6
    public function getDateSubYearsExpression($date, $years)
1276
    {
1277 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, self::DATE_INTERVAL_UNIT_YEAR);
1278
    }
1279
1280
    /**
1281
     * Returns the SQL for a date arithmetic expression.
1282
     *
1283
     * @param string  $date     The column or literal representing a date to perform the arithmetic operation on.
1284
     * @param string  $operator The arithmetic operator (+ or -).
1285
     * @param integer $interval The interval that shall be calculated into the date.
1286
     * @param string  $unit     The unit of the interval that shall be calculated into the date.
1287
     *                          One of the DATE_INTERVAL_UNIT_* constants.
1288
     *
1289
     * @return string
1290
     *
1291
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1292
     */
1293
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
1294
    {
1295
        throw DBALException::notSupported(__METHOD__);
1296
    }
1297
1298
    /**
1299
     * Returns the SQL bit AND comparison expression.
1300
     *
1301
     * @param string $value1
1302
     * @param string $value2
1303
     *
1304
     * @return string
1305
     */
1306 15
    public function getBitAndComparisonExpression($value1, $value2)
1307
    {
1308 15
        return '(' . $value1 . ' & ' . $value2 . ')';
1309
    }
1310
1311
    /**
1312
     * Returns the SQL bit OR comparison expression.
1313
     *
1314
     * @param string $value1
1315
     * @param string $value2
1316
     *
1317
     * @return string
1318
     */
1319 15
    public function getBitOrComparisonExpression($value1, $value2)
1320
    {
1321 15
        return '(' . $value1 . ' | ' . $value2 . ')';
1322
    }
1323
1324
    /**
1325
     * Returns the FOR UPDATE expression.
1326
     *
1327
     * @return string
1328
     */
1329
    public function getForUpdateSQL()
1330
    {
1331
        return 'FOR UPDATE';
1332
    }
1333
1334
    /**
1335
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1336
     *
1337
     * @param string       $fromClause The FROM clause to append the hint for the given lock mode to.
1338
     * @param integer|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1339
     *                                 be appended to the FROM clause.
1340
     *
1341
     * @return string
1342
     */
1343
    public function appendLockHint($fromClause, $lockMode)
1344
    {
1345
        return $fromClause;
1346
    }
1347
1348
    /**
1349
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1350
     *
1351
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1352
     * vendors allow to lighten this constraint up to be a real read lock.
1353
     *
1354
     * @return string
1355
     */
1356
    public function getReadLockSQL()
1357
    {
1358
        return $this->getForUpdateSQL();
1359
    }
1360
1361
    /**
1362
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1363
     *
1364
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1365
     *
1366
     * @return string
1367
     */
1368
    public function getWriteLockSQL()
1369
    {
1370
        return $this->getForUpdateSQL();
1371
    }
1372
1373
    /**
1374
     * Returns the SQL snippet to drop an existing database.
1375
     *
1376
     * @param string $database The name of the database that should be dropped.
1377
     *
1378
     * @return string
1379
     */
1380 4
    public function getDropDatabaseSQL($database)
1381
    {
1382 4
        return 'DROP DATABASE ' . $database;
1383
    }
1384
1385
    /**
1386
     * Returns the SQL snippet to drop an existing table.
1387
     *
1388
     * @param \Doctrine\DBAL\Schema\Table|string $table
1389
     *
1390
     * @return string
1391
     *
1392
     * @throws \InvalidArgumentException
1393
     */
1394 102
    public function getDropTableSQL($table)
1395
    {
1396 102
        $tableArg = $table;
1397
1398 102
        if ($table instanceof Table) {
1399 27
            $table = $table->getQuotedName($this);
1400 87
        } elseif (!is_string($table)) {
1401
            throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1402
        }
1403
1404 102
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1405 16
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1406 16
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1407
1408 16
            if ($eventArgs->isDefaultPrevented()) {
1409
                return $eventArgs->getSql();
1410
            }
1411
        }
1412
1413 102
        return 'DROP TABLE ' . $table;
1414
    }
1415
1416
    /**
1417
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1418
     *
1419
     * @param \Doctrine\DBAL\Schema\Table|string $table
1420
     *
1421
     * @return string
1422
     */
1423 2
    public function getDropTemporaryTableSQL($table)
1424
    {
1425 2
        return $this->getDropTableSQL($table);
1426
    }
1427
1428
    /**
1429
     * Returns the SQL to drop an index from a table.
1430
     *
1431
     * @param \Doctrine\DBAL\Schema\Index|string $index
1432
     * @param \Doctrine\DBAL\Schema\Table|string $table
1433
     *
1434
     * @return string
1435
     *
1436
     * @throws \InvalidArgumentException
1437
     */
1438 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...
1439
    {
1440 9
        if ($index instanceof Index) {
1441 8
            $index = $index->getQuotedName($this);
1442 1
        } elseif (!is_string($index)) {
1443
            throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1444
        }
1445
1446 9
        return 'DROP INDEX ' . $index;
1447
    }
1448
1449
    /**
1450
     * Returns the SQL to drop a constraint.
1451
     *
1452
     * @param \Doctrine\DBAL\Schema\Constraint|string $constraint
1453
     * @param \Doctrine\DBAL\Schema\Table|string      $table
1454
     *
1455
     * @return string
1456
     */
1457 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...
1458
    {
1459 31
        if (! $constraint instanceof Constraint) {
1460 23
            $constraint = new Identifier($constraint);
1461
        }
1462
1463 31
        if (! $table instanceof Table) {
1464 31
            $table = new Identifier($table);
1465
        }
1466
1467 31
        $constraint = $constraint->getQuotedName($this);
1468 31
        $table = $table->getQuotedName($this);
1469
1470 31
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1471
    }
1472
1473
    /**
1474
     * Returns the SQL to drop a foreign key.
1475
     *
1476
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint|string $foreignKey
1477
     * @param \Doctrine\DBAL\Schema\Table|string                $table
1478
     *
1479
     * @return string
1480
     */
1481 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...
1482
    {
1483 17
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1484 7
            $foreignKey = new Identifier($foreignKey);
1485
        }
1486
1487 17
        if (! $table instanceof Table) {
1488 17
            $table = new Identifier($table);
1489
        }
1490
1491 17
        $foreignKey = $foreignKey->getQuotedName($this);
1492 17
        $table = $table->getQuotedName($this);
1493
1494 17
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1495
    }
1496
1497
    /**
1498
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1499
     * on this platform.
1500
     *
1501
     * @param \Doctrine\DBAL\Schema\Table   $table
1502
     * @param integer                       $createFlags
1503
     *
1504
     * @return array The sequence of SQL statements.
1505
     *
1506
     * @throws \Doctrine\DBAL\DBALException
1507
     * @throws \InvalidArgumentException
1508
     */
1509 350
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1510
    {
1511 350
        if ( ! is_int($createFlags)) {
1512
            throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
1513
        }
1514
1515 350
        if (count($table->getColumns()) === 0) {
1516 16
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1517
        }
1518
1519 334
        $tableName = $table->getQuotedName($this);
1520 334
        $options = $table->getOptions();
1521 334
        $options['uniqueConstraints'] = [];
1522 334
        $options['indexes'] = [];
1523 334
        $options['primary'] = [];
1524
1525 334
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1526 313
            foreach ($table->getIndexes() as $index) {
1527
                /* @var $index Index */
1528 232
                if ($index->isPrimary()) {
1529 175
                    $options['primary']       = $index->getQuotedColumns($this);
1530 175
                    $options['primary_index'] = $index;
1531
                } else {
1532 232
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1533
                }
1534
            }
1535
        }
1536
1537 334
        $columnSql = [];
1538 334
        $columns = [];
1539
1540 334
        foreach ($table->getColumns() as $column) {
1541
            /* @var \Doctrine\DBAL\Schema\Column $column */
1542
1543 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...
1544 16
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1545 16
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1546
1547 16
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1548
1549 16
                if ($eventArgs->isDefaultPrevented()) {
1550
                    continue;
1551
                }
1552
            }
1553
1554 334
            $columnData = $column->toArray();
1555 334
            $columnData['name'] = $column->getQuotedName($this);
1556 334
            $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false;
1557 334
            $columnData['comment'] = $this->getColumnComment($column);
1558
1559 334
            if (strtolower($columnData['type']) == "string" && $columnData['length'] === null) {
1560 134
                $columnData['length'] = 255;
1561
            }
1562
1563 334
            if (in_array($column->getName(), $options['primary'])) {
1564 157
                $columnData['primary'] = true;
1565
            }
1566
1567 334
            $columns[$columnData['name']] = $columnData;
1568
        }
1569
1570 334
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1571 168
            $options['foreignKeys'] = [];
1572 168
            foreach ($table->getForeignKeys() as $fkConstraint) {
1573 28
                $options['foreignKeys'][] = $fkConstraint;
1574
            }
1575
        }
1576
1577 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...
1578 16
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1579 16
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1580
1581 16
            if ($eventArgs->isDefaultPrevented()) {
1582
                return array_merge($eventArgs->getSql(), $columnSql);
1583
            }
1584
        }
1585
1586 334
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1587 334
        if ($this->supportsCommentOnStatement()) {
1588 111
            foreach ($table->getColumns() as $column) {
1589 111
                $comment = $this->getColumnComment($column);
1590
1591 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...
1592 111
                    $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1593
                }
1594
            }
1595
        }
1596
1597 334
        return array_merge($sql, $columnSql);
1598
    }
1599
1600
    /**
1601
     * @param string $tableName
1602
     * @param string $columnName
1603
     * @param string $comment
1604
     *
1605
     * @return string
1606
     */
1607 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...
1608
    {
1609 31
        $tableName = new Identifier($tableName);
1610 31
        $columnName = new Identifier($columnName);
1611 31
        $comment = $this->quoteStringLiteral($comment);
1612
1613 31
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . "." . $columnName->getQuotedName($this) .
1614 31
            " IS " . $comment;
1615
    }
1616
1617
    /**
1618
     * Returns the SQL to create inline comment on a column.
1619
     *
1620
     * @param string $comment
1621
     *
1622
     * @return string
1623
     *
1624
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1625
     */
1626 31
    public function getInlineColumnCommentSQL($comment)
1627
    {
1628 31
        if (! $this->supportsInlineColumnComments()) {
1629 13
            throw DBALException::notSupported(__METHOD__);
1630
        }
1631
1632 18
        return "COMMENT " . $this->quoteStringLiteral($comment);
1633
    }
1634
1635
    /**
1636
     * Returns the SQL used to create a table.
1637
     *
1638
     * @param string $tableName
1639
     * @param array  $columns
1640
     * @param array  $options
1641
     *
1642
     * @return array
1643
     */
1644 23
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1645
    {
1646 23
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1647
1648 23
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1649
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1650
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1651
            }
1652
        }
1653
1654 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...
1655 10
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1656
        }
1657
1658 23
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1659
            foreach ($options['indexes'] as $index => $definition) {
1660
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1661
            }
1662
        }
1663
1664 23
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1665
1666 23
        $check = $this->getCheckDeclarationSQL($columns);
1667 23
        if ( ! empty($check)) {
1668 1
            $query .= ', ' . $check;
1669
        }
1670 23
        $query .= ')';
1671
1672 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...
1673
1674 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...
1675 3
            foreach ((array) $options['foreignKeys'] as $definition) {
1676 3
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1677
            }
1678
        }
1679
1680 23
        return $sql;
1681
    }
1682
1683
    /**
1684
     * @return string
1685
     */
1686 2
    public function getCreateTemporaryTableSnippetSQL()
1687
    {
1688 2
        return "CREATE TEMPORARY TABLE";
1689
    }
1690
1691
    /**
1692
     * Returns the SQL to create a sequence on this platform.
1693
     *
1694
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1695
     *
1696
     * @return string
1697
     *
1698
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1699
     */
1700
    public function getCreateSequenceSQL(Sequence $sequence)
1701
    {
1702
        throw DBALException::notSupported(__METHOD__);
1703
    }
1704
1705
    /**
1706
     * Returns the SQL to change a sequence on this platform.
1707
     *
1708
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1709
     *
1710
     * @return string
1711
     *
1712
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1713
     */
1714
    public function getAlterSequenceSQL(Sequence $sequence)
1715
    {
1716
        throw DBALException::notSupported(__METHOD__);
1717
    }
1718
1719
    /**
1720
     * Returns the SQL to create a constraint on a table on this platform.
1721
     *
1722
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1723
     * @param \Doctrine\DBAL\Schema\Table|string $table
1724
     *
1725
     * @return string
1726
     *
1727
     * @throws \InvalidArgumentException
1728
     */
1729 14
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1730
    {
1731 14
        if ($table instanceof Table) {
1732
            $table = $table->getQuotedName($this);
1733
        }
1734
1735 14
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1736
1737 14
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1738
1739 14
        $referencesClause = '';
1740 14
        if ($constraint instanceof Index) {
1741 14
            if ($constraint->isPrimary()) {
1742 14
                $query .= ' PRIMARY KEY';
1743 11
            } elseif ($constraint->isUnique()) {
1744 11
                $query .= ' UNIQUE';
1745
            } else {
1746
                throw new \InvalidArgumentException(
1747 14
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1748
                );
1749
            }
1750 11
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1751 11
            $query .= ' FOREIGN KEY';
1752
1753 11
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1754 11
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1755
        }
1756 14
        $query .= ' '.$columnList.$referencesClause;
1757
1758 14
        return $query;
1759
    }
1760
1761
    /**
1762
     * Returns the SQL to create an index on a table on this platform.
1763
     *
1764
     * @param \Doctrine\DBAL\Schema\Index        $index
1765
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1766
     *
1767
     * @return string
1768
     *
1769
     * @throws \InvalidArgumentException
1770
     */
1771 135
    public function getCreateIndexSQL(Index $index, $table)
1772
    {
1773 135
        if ($table instanceof Table) {
1774 1
            $table = $table->getQuotedName($this);
1775
        }
1776 135
        $name = $index->getQuotedName($this);
1777 135
        $columns = $index->getQuotedColumns($this);
1778
1779 135
        if (count($columns) == 0) {
1780
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1781
        }
1782
1783 135
        if ($index->isPrimary()) {
1784 16
            return $this->getCreatePrimaryKeySQL($index, $table);
1785
        }
1786
1787 121
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1788 121
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index);
1789
1790 121
        return $query;
1791
    }
1792
1793
    /**
1794
     * Adds condition for partial index.
1795
     *
1796
     * @param \Doctrine\DBAL\Schema\Index $index
1797
     *
1798
     * @return string
1799
     */
1800 158
    protected function getPartialIndexSQL(Index $index)
1801
    {
1802 158
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1803 4
            return  ' WHERE ' . $index->getOption('where');
1804
        }
1805
1806 154
        return '';
1807
    }
1808
1809
    /**
1810
     * Adds additional flags for index generation.
1811
     *
1812
     * @param \Doctrine\DBAL\Schema\Index $index
1813
     *
1814
     * @return string
1815
     */
1816 60
    protected function getCreateIndexSQLFlags(Index $index)
1817
    {
1818 60
        return $index->isUnique() ? 'UNIQUE ' : '';
1819
    }
1820
1821
    /**
1822
     * Returns the SQL to create an unnamed primary key constraint.
1823
     *
1824
     * @param \Doctrine\DBAL\Schema\Index        $index
1825
     * @param \Doctrine\DBAL\Schema\Table|string $table
1826
     *
1827
     * @return string
1828
     */
1829 12
    public function getCreatePrimaryKeySQL(Index $index, $table)
1830
    {
1831 12
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
1832
    }
1833
1834
    /**
1835
     * Returns the SQL to create a named schema.
1836
     *
1837
     * @param string $schemaName
1838
     *
1839
     * @return string
1840
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1841
     */
1842 9
    public function getCreateSchemaSQL($schemaName)
1843
    {
1844 9
        throw DBALException::notSupported(__METHOD__);
1845
    }
1846
1847
    /**
1848
     * Quotes a string so that it can be safely used as a table or column name,
1849
     * even if it is a reserved word of the platform. This also detects identifier
1850
     * chains separated by dot and quotes them independently.
1851
     *
1852
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1853
     * you SHOULD use them. In general, they end up causing way more
1854
     * problems than they solve.
1855
     *
1856
     * @param string $str The identifier name to be quoted.
1857
     *
1858
     * @return string The quoted identifier string.
1859
     */
1860 348
    public function quoteIdentifier($str)
1861
    {
1862 348
        if (strpos($str, ".") !== false) {
1863 16
            $parts = array_map([$this, "quoteSingleIdentifier"], explode(".", $str));
1864
1865 16
            return implode(".", $parts);
1866
        }
1867
1868 348
        return $this->quoteSingleIdentifier($str);
1869
    }
1870
1871
    /**
1872
     * Quotes a single identifier (no dot chain separation).
1873
     *
1874
     * @param string $str The identifier name to be quoted.
1875
     *
1876
     * @return string The quoted identifier string.
1877
     */
1878 318
    public function quoteSingleIdentifier($str)
1879
    {
1880 318
        $c = $this->getIdentifierQuoteCharacter();
1881
1882 318
        return $c . str_replace($c, $c.$c, $str) . $c;
1883
    }
1884
1885
    /**
1886
     * Returns the SQL to create a new foreign key.
1887
     *
1888
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key constraint.
1889
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
1890
     *
1891
     * @return string
1892
     */
1893 67
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1894
    {
1895 67
        if ($table instanceof Table) {
1896 1
            $table = $table->getQuotedName($this);
1897
        }
1898
1899 67
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1900
1901 67
        return $query;
1902
    }
1903
1904
    /**
1905
     * Gets the SQL statements for altering an existing table.
1906
     *
1907
     * This method returns an array of SQL statements, since some platforms need several statements.
1908
     *
1909
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1910
     *
1911
     * @return array
1912
     *
1913
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1914
     */
1915
    public function getAlterTableSQL(TableDiff $diff)
1916
    {
1917
        throw DBALException::notSupported(__METHOD__);
1918
    }
1919
1920
    /**
1921
     * @param \Doctrine\DBAL\Schema\Column    $column
1922
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1923
     * @param array                           $columnSql
1924
     *
1925
     * @return boolean
1926
     */
1927 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...
1928
    {
1929 85
        if (null === $this->_eventManager) {
1930 68
            return false;
1931
        }
1932
1933 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1934 1
            return false;
1935
        }
1936
1937 16
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1938 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1939
1940 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1941
1942 16
        return $eventArgs->isDefaultPrevented();
1943
    }
1944
1945
    /**
1946
     * @param \Doctrine\DBAL\Schema\Column    $column
1947
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1948
     * @param array                           $columnSql
1949
     *
1950
     * @return boolean
1951
     */
1952 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...
1953
    {
1954 69
        if (null === $this->_eventManager) {
1955 52
            return false;
1956
        }
1957
1958 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
1959 1
            return false;
1960
        }
1961
1962 16
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
1963 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
1964
1965 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1966
1967 16
        return $eventArgs->isDefaultPrevented();
1968
    }
1969
1970
    /**
1971
     * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff
1972
     * @param \Doctrine\DBAL\Schema\TableDiff  $diff
1973
     * @param array                            $columnSql
1974
     *
1975
     * @return boolean
1976
     */
1977 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...
1978
    {
1979 168
        if (null === $this->_eventManager) {
1980 140
            return false;
1981
        }
1982
1983 28
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
1984 12
            return false;
1985
        }
1986
1987 16
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
1988 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
1989
1990 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1991
1992 16
        return $eventArgs->isDefaultPrevented();
1993
    }
1994
1995
    /**
1996
     * @param string                          $oldColumnName
1997
     * @param \Doctrine\DBAL\Schema\Column    $column
1998
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1999
     * @param array                           $columnSql
2000
     *
2001
     * @return boolean
2002
     */
2003 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...
2004
    {
2005 68
        if (null === $this->_eventManager) {
2006 52
            return false;
2007
        }
2008
2009 16
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2010
            return false;
2011
        }
2012
2013 16
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2014 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2015
2016 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2017
2018 16
        return $eventArgs->isDefaultPrevented();
2019
    }
2020
2021
    /**
2022
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2023
     * @param array                           $sql
2024
     *
2025
     * @return boolean
2026
     */
2027 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...
2028
    {
2029 315
        if (null === $this->_eventManager) {
2030 280
            return false;
2031
        }
2032
2033 35
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2034 19
            return false;
2035
        }
2036
2037 16
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2038 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2039
2040 16
        $sql = array_merge($sql, $eventArgs->getSql());
2041
2042 16
        return $eventArgs->isDefaultPrevented();
2043
    }
2044
2045
    /**
2046
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2047
     *
2048
     * @return array
2049
     */
2050 283
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2051
    {
2052 283
        $tableName = $diff->getName($this)->getQuotedName($this);
2053
2054 283
        $sql = [];
2055 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...
2056 283
            foreach ($diff->removedForeignKeys as $foreignKey) {
2057 21
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2058
            }
2059 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2060 17
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2061
            }
2062
        }
2063
2064 283
        foreach ($diff->removedIndexes as $index) {
2065 8
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2066
        }
2067 283
        foreach ($diff->changedIndexes as $index) {
2068 11
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2069
        }
2070
2071 283
        return $sql;
2072
    }
2073
2074
    /**
2075
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2076
     *
2077
     * @return array
2078
     */
2079 283
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2080
    {
2081 283
        $tableName = (false !== $diff->newName)
2082 30
            ? $diff->getNewName()->getQuotedName($this)
2083 283
            : $diff->getName($this)->getQuotedName($this);
2084
2085 283
        $sql = [];
2086
2087 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...
2088 283
            foreach ($diff->addedForeignKeys as $foreignKey) {
2089 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2090
            }
2091
2092 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2093 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2094
            }
2095
        }
2096
2097 283
        foreach ($diff->addedIndexes as $index) {
2098 2
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2099
        }
2100
2101 283
        foreach ($diff->changedIndexes as $index) {
2102 11
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2103
        }
2104
2105 283
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2106 75
            $oldIndexName = new Identifier($oldIndexName);
2107 75
            $sql          = array_merge(
2108 75
                $sql,
2109 75
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2110
            );
2111
        }
2112
2113 283
        return $sql;
2114
    }
2115
2116
    /**
2117
     * Returns the SQL for renaming an index on a table.
2118
     *
2119
     * @param string                      $oldIndexName The name of the index to rename from.
2120
     * @param \Doctrine\DBAL\Schema\Index $index        The definition of the index to rename to.
2121
     * @param string                      $tableName    The table to rename the given index on.
2122
     *
2123
     * @return array The sequence of SQL statements for renaming the given index.
2124
     */
2125 5
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2126
    {
2127
        return [
2128 5
            $this->getDropIndexSQL($oldIndexName, $tableName),
2129 5
            $this->getCreateIndexSQL($index, $tableName)
2130
        ];
2131
    }
2132
2133
    /**
2134
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2135
     *
2136
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2137
     *
2138
     * @return array
2139
     */
2140
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2141
    {
2142
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2143
    }
2144
2145
    /**
2146
     * Gets declaration of a number of fields in bulk.
2147
     *
2148
     * @param array $fields A multidimensional associative array.
2149
     *                      The first dimension determines the field name, while the second
2150
     *                      dimension is keyed with the name of the properties
2151
     *                      of the field being declared as array indexes. Currently, the types
2152
     *                      of supported field properties are as follows:
2153
     *
2154
     *      length
2155
     *          Integer value that determines the maximum length of the text
2156
     *          field. If this argument is missing the field should be
2157
     *          declared to have the longest length allowed by the DBMS.
2158
     *
2159
     *      default
2160
     *          Text value to be used as default for this field.
2161
     *
2162
     *      notnull
2163
     *          Boolean flag that indicates whether this field is constrained
2164
     *          to not be set to null.
2165
     *      charset
2166
     *          Text value with the default CHARACTER SET for this field.
2167
     *      collation
2168
     *          Text value with the default COLLATION for this field.
2169
     *      unique
2170
     *          unique constraint
2171
     *
2172
     * @return string
2173
     */
2174 334
    public function getColumnDeclarationListSQL(array $fields)
2175
    {
2176 334
        $queryFields = [];
2177
2178 334
        foreach ($fields as $fieldName => $field) {
2179 334
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2180
        }
2181
2182 334
        return implode(', ', $queryFields);
2183
    }
2184
2185
    /**
2186
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2187
     * field to be used in statements like CREATE TABLE.
2188
     *
2189
     * @param string $name  The name the field to be declared.
2190
     * @param array  $field An associative array with the name of the properties
2191
     *                      of the field being declared as array indexes. Currently, the types
2192
     *                      of supported field properties are as follows:
2193
     *
2194
     *      length
2195
     *          Integer value that determines the maximum length of the text
2196
     *          field. If this argument is missing the field should be
2197
     *          declared to have the longest length allowed by the DBMS.
2198
     *
2199
     *      default
2200
     *          Text value to be used as default for this field.
2201
     *
2202
     *      notnull
2203
     *          Boolean flag that indicates whether this field is constrained
2204
     *          to not be set to null.
2205
     *      charset
2206
     *          Text value with the default CHARACTER SET for this field.
2207
     *      collation
2208
     *          Text value with the default COLLATION for this field.
2209
     *      unique
2210
     *          unique constraint
2211
     *      check
2212
     *          column check constraint
2213
     *      columnDefinition
2214
     *          a string that defines the complete column
2215
     *
2216
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2217
     */
2218 364
    public function getColumnDeclarationSQL($name, array $field)
2219
    {
2220 364
        if (isset($field['columnDefinition'])) {
2221 13
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2222
        } else {
2223 352
            $default = $this->getDefaultValueDeclarationSQL($field);
2224
2225 352
            $charset = (isset($field['charset']) && $field['charset']) ?
2226 352
                    ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2227
2228 352
            $collation = (isset($field['collation']) && $field['collation']) ?
2229 352
                    ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2230
2231 352
            $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
2232
2233 352
            $unique = (isset($field['unique']) && $field['unique']) ?
2234 352
                    ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2235
2236 352
            $check = (isset($field['check']) && $field['check']) ?
2237 352
                    ' ' . $field['check'] : '';
2238
2239 352
            $typeDecl = $field['type']->getSQLDeclaration($field, $this);
2240 352
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2241
2242 352
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2243 45
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2244
            }
2245
        }
2246
2247 364
        return $name . ' ' . $columnDef;
2248
    }
2249
2250
    /**
2251
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2252
     *
2253
     * @param array $columnDef
2254
     *
2255
     * @return string
2256
     */
2257 120
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2258
    {
2259 120
        $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
2260 120
            ? 10 : $columnDef['precision'];
2261 120
        $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
2262 120
            ? 0 : $columnDef['scale'];
2263
2264 120
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2265
    }
2266
2267
    /**
2268
     * Obtains DBMS specific SQL code portion needed to set a default value
2269
     * declaration to be used in statements like CREATE TABLE.
2270
     *
2271
     * @param array $field The field definition array.
2272
     *
2273
     * @return string DBMS specific SQL code portion needed to set a default value.
2274
     */
2275 410
    public function getDefaultValueDeclarationSQL($field)
2276
    {
2277 410
        $default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
2278
2279 410
        if (isset($field['default'])) {
2280 64
            $default = " DEFAULT '".$field['default']."'";
2281 64
            if (isset($field['type'])) {
2282 64
                $type = $field['type'];
2283 64
                if ($type instanceof Types\IntegerType ||
2284 59
                    $type instanceof Types\BigIntType ||
2285 64
                    $type instanceof Types\SmallIntType
2286
                ) {
2287 20
                    $default = " DEFAULT ".$field['default'];
2288 46
                } elseif (($type instanceof Types\DateTimeType || $type instanceof Types\DateTimeTzType)
2289 46
                    && $field['default'] == $this->getCurrentTimestampSQL()) {
2290 13
                    $default = " DEFAULT ".$this->getCurrentTimestampSQL();
2291 33
                } elseif ($type instanceof Types\TimeType && $field['default'] == $this->getCurrentTimeSQL()) {
2292
                    $default = " DEFAULT ".$this->getCurrentTimeSQL();
2293 33
                } elseif ($type instanceof Types\DateType && $field['default'] == $this->getCurrentDateSQL()) {
2294
                    $default = " DEFAULT ".$this->getCurrentDateSQL();
2295 33
                } elseif ($type instanceof Types\BooleanType) {
2296 13
                    $default = " DEFAULT '" . $this->convertBooleans($field['default']) . "'";
2297
                }
2298
            }
2299
        }
2300
2301 410
        return $default;
2302
    }
2303
2304
    /**
2305
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2306
     * declaration to be used in statements like CREATE TABLE.
2307
     *
2308
     * @param array $definition The check definition.
2309
     *
2310
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2311
     */
2312 117
    public function getCheckDeclarationSQL(array $definition)
2313
    {
2314 117
        $constraints = [];
2315 117
        foreach ($definition as $field => $def) {
2316 117
            if (is_string($def)) {
2317
                $constraints[] = 'CHECK (' . $def . ')';
2318
            } else {
2319 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...
2320 5
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2321
                }
2322
2323 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...
2324 117
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2325
                }
2326
            }
2327
        }
2328
2329 117
        return implode(', ', $constraints);
2330
    }
2331
2332
    /**
2333
     * Obtains DBMS specific SQL code portion needed to set a unique
2334
     * constraint declaration to be used in statements like CREATE TABLE.
2335
     *
2336
     * @param string                      $name  The name of the unique constraint.
2337
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2338
     *
2339
     * @return string DBMS specific SQL code portion needed to set a constraint.
2340
     *
2341
     * @throws \InvalidArgumentException
2342
     */
2343 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...
2344
    {
2345 24
        $columns = $index->getQuotedColumns($this);
2346 24
        $name = new Identifier($name);
2347
2348 24
        if (count($columns) === 0) {
2349
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2350
        }
2351
2352 24
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2353 24
             . $this->getIndexFieldDeclarationListSQL($columns)
2354 24
             . ')' . $this->getPartialIndexSQL($index);
2355
    }
2356
2357
    /**
2358
     * Obtains DBMS specific SQL code portion needed to set an index
2359
     * declaration to be used in statements like CREATE TABLE.
2360
     *
2361
     * @param string                      $name  The name of the index.
2362
     * @param \Doctrine\DBAL\Schema\Index $index The index definition.
2363
     *
2364
     * @return string DBMS specific SQL code portion needed to set an index.
2365
     *
2366
     * @throws \InvalidArgumentException
2367
     */
2368 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...
2369
    {
2370 36
        $columns = $index->getQuotedColumns($this);
2371 36
        $name = new Identifier($name);
2372
2373 36
        if (count($columns) === 0) {
2374
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
2375
        }
2376
2377 36
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2378 36
            . $this->getIndexFieldDeclarationListSQL($columns)
2379 36
            . ')' . $this->getPartialIndexSQL($index);
2380
    }
2381
2382
    /**
2383
     * Obtains SQL code portion needed to create a custom column,
2384
     * e.g. when a field has the "columnDefinition" keyword.
2385
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2386
     *
2387
     * @param array $columnDef
2388
     *
2389
     * @return string
2390
     */
2391 17
    public function getCustomTypeDeclarationSQL(array $columnDef)
2392
    {
2393 17
        return $columnDef['columnDefinition'];
2394
    }
2395
2396
    /**
2397
     * Obtains DBMS specific SQL code portion needed to set an index
2398
     * declaration to be used in statements like CREATE TABLE.
2399
     *
2400
     * @param array $fields
2401
     *
2402
     * @return string
2403
     */
2404 222
    public function getIndexFieldDeclarationListSQL(array $fields)
2405
    {
2406 222
        $ret = [];
2407
2408 222
        foreach ($fields as $field => $definition) {
2409 222
            if (is_array($definition)) {
2410
                $ret[] = $field;
2411
            } else {
2412 222
                $ret[] = $definition;
2413
            }
2414
        }
2415
2416 222
        return implode(', ', $ret);
2417
    }
2418
2419
    /**
2420
     * Returns the required SQL string that fits between CREATE ... TABLE
2421
     * to create the table as a temporary table.
2422
     *
2423
     * Should be overridden in driver classes to return the correct string for the
2424
     * specific database type.
2425
     *
2426
     * The default is to return the string "TEMPORARY" - this will result in a
2427
     * SQL error for any database that does not support temporary tables, or that
2428
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2429
     *
2430
     * @return string The string required to be placed between "CREATE" and "TABLE"
2431
     *                to generate a temporary table, if possible.
2432
     */
2433
    public function getTemporaryTableSQL()
2434
    {
2435
        return 'TEMPORARY';
2436
    }
2437
2438
    /**
2439
     * Some vendors require temporary table names to be qualified specially.
2440
     *
2441
     * @param string $tableName
2442
     *
2443
     * @return string
2444
     */
2445
    public function getTemporaryTableName($tableName)
2446
    {
2447
        return $tableName;
2448
    }
2449
2450
    /**
2451
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2452
     * of a field declaration to be used in statements like CREATE TABLE.
2453
     *
2454
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2455
     *
2456
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2457
     *                of a field declaration.
2458
     */
2459 101
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2460
    {
2461 101
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2462 89
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2463
2464 89
        return $sql;
2465
    }
2466
2467
    /**
2468
     * Returns the FOREIGN KEY query section dealing with non-standard options
2469
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2470
     *
2471
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key definition.
2472
     *
2473
     * @return string
2474
     */
2475 85
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2476
    {
2477 85
        $query = '';
2478 85
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2479 4
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2480
        }
2481 85
        if ($foreignKey->hasOption('onDelete')) {
2482 8
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2483
        }
2484
2485 85
        return $query;
2486
    }
2487
2488
    /**
2489
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2490
     *
2491
     * @param string $action The foreign key referential action.
2492
     *
2493
     * @return string
2494
     *
2495
     * @throws \InvalidArgumentException if unknown referential action given
2496
     */
2497 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...
2498
    {
2499 106
        $upper = strtoupper($action);
2500
        switch ($upper) {
2501 106
            case 'CASCADE':
2502 72
            case 'SET NULL':
2503 53
            case 'NO ACTION':
2504 42
            case 'RESTRICT':
2505 30
            case 'SET DEFAULT':
2506 91
                return $upper;
2507
            default:
2508 15
                throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper);
2509
        }
2510
    }
2511
2512
    /**
2513
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2514
     * of a field declaration to be used in statements like CREATE TABLE.
2515
     *
2516
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey
2517
     *
2518
     * @return string
2519
     *
2520
     * @throws \InvalidArgumentException
2521
     */
2522 61
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2523
    {
2524 61
        $sql = '';
2525 61
        if (strlen($foreignKey->getName())) {
2526 49
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2527
        }
2528 61
        $sql .= 'FOREIGN KEY (';
2529
2530 61
        if (count($foreignKey->getLocalColumns()) === 0) {
2531
            throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
2532
        }
2533 61
        if (count($foreignKey->getForeignColumns()) === 0) {
2534
            throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
2535
        }
2536 61
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2537
            throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2538
        }
2539
2540 61
        $sql .= implode(', ', $foreignKey->getQuotedLocalColumns($this))
2541 61
              . ') REFERENCES '
2542 61
              . $foreignKey->getQuotedForeignTableName($this) . ' ('
2543 61
              . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2544
2545 61
        return $sql;
2546
    }
2547
2548
    /**
2549
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2550
     * of a field declaration to be used in statements like CREATE TABLE.
2551
     *
2552
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2553
     *                of a field declaration.
2554
     */
2555
    public function getUniqueFieldDeclarationSQL()
2556
    {
2557
        return 'UNIQUE';
2558
    }
2559
2560
    /**
2561
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2562
     * of a field declaration to be used in statements like CREATE TABLE.
2563
     *
2564
     * @param string $charset The name of the charset.
2565
     *
2566
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2567
     *                of a field declaration.
2568
     */
2569
    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...
2570
    {
2571
        return '';
2572
    }
2573
2574
    /**
2575
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2576
     * of a field declaration to be used in statements like CREATE TABLE.
2577
     *
2578
     * @param string $collation The name of the collation.
2579
     *
2580
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2581
     *                of a field declaration.
2582
     */
2583 1
    public function getColumnCollationDeclarationSQL($collation)
2584
    {
2585 1
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2586
    }
2587
2588
    /**
2589
     * Whether the platform prefers sequences for ID generation.
2590
     * Subclasses should override this method to return TRUE if they prefer sequences.
2591
     *
2592
     * @return boolean
2593
     */
2594 5
    public function prefersSequences()
2595
    {
2596 5
        return false;
2597
    }
2598
2599
    /**
2600
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2601
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2602
     *
2603
     * @return boolean
2604
     */
2605 5
    public function prefersIdentityColumns()
2606
    {
2607 5
        return false;
2608
    }
2609
2610
    /**
2611
     * Some platforms need the boolean values to be converted.
2612
     *
2613
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2614
     *
2615
     * Note: if the input is not a boolean the original input might be returned.
2616
     *
2617
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2618
     * This method should handle the literal case
2619
     *
2620
     * @param mixed $item A boolean or an array of them.
2621
     *
2622
     * @return mixed A boolean database value or an array of them.
2623
     */
2624 20
    public function convertBooleans($item)
2625
    {
2626 20
        if (is_array($item)) {
2627
            foreach ($item as $k => $value) {
2628
                if (is_bool($value)) {
2629
                    $item[$k] = (int) $value;
2630
                }
2631
            }
2632 20
        } elseif (is_bool($item)) {
2633 19
            $item = (int) $item;
2634
        }
2635
2636 20
        return $item;
2637
    }
2638
2639
    /**
2640
     * Some platforms have boolean literals that needs to be correctly converted
2641
     *
2642
     * The default conversion tries to convert value into bool "(bool)$item"
2643
     *
2644
     * @param mixed $item
2645
     *
2646
     * @return bool|null
2647
     */
2648 40
    public function convertFromBoolean($item)
2649
    {
2650 40
        return null === $item ? null: (bool) $item ;
2651
    }
2652
2653
    /**
2654
     * This method should handle the prepared statements case. When there is no
2655
     * distinction, it's OK to use the same method.
2656
     *
2657
     * Note: if the input is not a boolean the original input might be returned.
2658
     *
2659
     * @param mixed $item A boolean or an array of them.
2660
     *
2661
     * @return mixed A boolean database value or an array of them.
2662
     */
2663 7
    public function convertBooleansToDatabaseValue($item)
2664
    {
2665 7
        return $this->convertBooleans($item);
2666
    }
2667
2668
    /**
2669
     * Returns the SQL specific for the platform to get the current date.
2670
     *
2671
     * @return string
2672
     */
2673 1
    public function getCurrentDateSQL()
2674
    {
2675 1
        return 'CURRENT_DATE';
2676
    }
2677
2678
    /**
2679
     * Returns the SQL specific for the platform to get the current time.
2680
     *
2681
     * @return string
2682
     */
2683
    public function getCurrentTimeSQL()
2684
    {
2685
        return 'CURRENT_TIME';
2686
    }
2687
2688
    /**
2689
     * Returns the SQL specific for the platform to get the current timestamp
2690
     *
2691
     * @return string
2692
     */
2693 15
    public function getCurrentTimestampSQL()
2694
    {
2695 15
        return 'CURRENT_TIMESTAMP';
2696
    }
2697
2698
    /**
2699
     * Returns the SQL for a given transaction isolation level Connection constant.
2700
     *
2701
     * @param integer $level
2702
     *
2703
     * @return string
2704
     *
2705
     * @throws \InvalidArgumentException
2706
     */
2707 9
    protected function _getTransactionIsolationLevelSQL($level)
2708
    {
2709
        switch ($level) {
2710 9
            case Connection::TRANSACTION_READ_UNCOMMITTED:
2711 9
                return 'READ UNCOMMITTED';
2712 9
            case Connection::TRANSACTION_READ_COMMITTED:
2713 9
                return 'READ COMMITTED';
2714 9
            case Connection::TRANSACTION_REPEATABLE_READ:
2715 9
                return 'REPEATABLE READ';
2716 9
            case Connection::TRANSACTION_SERIALIZABLE:
2717 9
                return 'SERIALIZABLE';
2718
            default:
2719
                throw new \InvalidArgumentException('Invalid isolation level:' . $level);
2720
        }
2721
    }
2722
2723
    /**
2724
     * @return string
2725
     *
2726
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2727
     */
2728 1
    public function getListDatabasesSQL()
2729
    {
2730 1
        throw DBALException::notSupported(__METHOD__);
2731
    }
2732
2733
    /**
2734
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2735
     *
2736
     * @return string
2737
     *
2738
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2739
     */
2740
    public function getListNamespacesSQL()
2741
    {
2742
        throw DBALException::notSupported(__METHOD__);
2743
    }
2744
2745
    /**
2746
     * @param string $database
2747
     *
2748
     * @return string
2749
     *
2750
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2751
     */
2752
    public function getListSequencesSQL($database)
2753
    {
2754
        throw DBALException::notSupported(__METHOD__);
2755
    }
2756
2757
    /**
2758
     * @param string $table
2759
     *
2760
     * @return string
2761
     *
2762
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2763
     */
2764
    public function getListTableConstraintsSQL($table)
2765
    {
2766
        throw DBALException::notSupported(__METHOD__);
2767
    }
2768
2769
    /**
2770
     * @param string      $table
2771
     * @param string|null $database
2772
     *
2773
     * @return string
2774
     *
2775
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2776
     */
2777
    public function getListTableColumnsSQL($table, $database = null)
2778
    {
2779
        throw DBALException::notSupported(__METHOD__);
2780
    }
2781
2782
    /**
2783
     * @return string
2784
     *
2785
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2786
     */
2787
    public function getListTablesSQL()
2788
    {
2789
        throw DBALException::notSupported(__METHOD__);
2790
    }
2791
2792
    /**
2793
     * @return string
2794
     *
2795
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2796
     */
2797
    public function getListUsersSQL()
2798
    {
2799
        throw DBALException::notSupported(__METHOD__);
2800
    }
2801
2802
    /**
2803
     * Returns the SQL to list all views of a database or user.
2804
     *
2805
     * @param string $database
2806
     *
2807
     * @return string
2808
     *
2809
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2810
     */
2811
    public function getListViewsSQL($database)
2812
    {
2813
        throw DBALException::notSupported(__METHOD__);
2814
    }
2815
2816
    /**
2817
     * Returns the list of indexes for the current database.
2818
     *
2819
     * The current database parameter is optional but will always be passed
2820
     * when using the SchemaManager API and is the database the given table is in.
2821
     *
2822
     * Attention: Some platforms only support currentDatabase when they
2823
     * are connected with that database. Cross-database information schema
2824
     * requests may be impossible.
2825
     *
2826
     * @param string $table
2827
     * @param string $currentDatabase
2828
     *
2829
     * @return string
2830
     *
2831
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2832
     */
2833
    public function getListTableIndexesSQL($table, $currentDatabase = null)
2834
    {
2835
        throw DBALException::notSupported(__METHOD__);
2836
    }
2837
2838
    /**
2839
     * @param string $table
2840
     *
2841
     * @return string
2842
     *
2843
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2844
     */
2845
    public function getListTableForeignKeysSQL($table)
2846
    {
2847
        throw DBALException::notSupported(__METHOD__);
2848
    }
2849
2850
    /**
2851
     * @param string $name
2852
     * @param string $sql
2853
     *
2854
     * @return string
2855
     *
2856
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2857
     */
2858
    public function getCreateViewSQL($name, $sql)
2859
    {
2860
        throw DBALException::notSupported(__METHOD__);
2861
    }
2862
2863
    /**
2864
     * @param string $name
2865
     *
2866
     * @return string
2867
     *
2868
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2869
     */
2870
    public function getDropViewSQL($name)
2871
    {
2872
        throw DBALException::notSupported(__METHOD__);
2873
    }
2874
2875
    /**
2876
     * Returns the SQL snippet to drop an existing sequence.
2877
     *
2878
     * @param Sequence|string $sequence
2879
     *
2880
     * @return string
2881
     *
2882
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2883
     */
2884
    public function getDropSequenceSQL($sequence)
2885
    {
2886
        throw DBALException::notSupported(__METHOD__);
2887
    }
2888
2889
    /**
2890
     * @param string $sequenceName
2891
     *
2892
     * @return string
2893
     *
2894
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2895
     */
2896
    public function getSequenceNextValSQL($sequenceName)
2897
    {
2898
        throw DBALException::notSupported(__METHOD__);
2899
    }
2900
2901
    /**
2902
     * Returns the SQL to create a new database.
2903
     *
2904
     * @param string $database The name of the database that should be created.
2905
     *
2906
     * @return string
2907
     *
2908
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2909
     */
2910 1
    public function getCreateDatabaseSQL($database)
2911
    {
2912 1
        throw DBALException::notSupported(__METHOD__);
2913
    }
2914
2915
    /**
2916
     * Returns the SQL to set the transaction isolation level.
2917
     *
2918
     * @param integer $level
2919
     *
2920
     * @return string
2921
     *
2922
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2923
     */
2924
    public function getSetTransactionIsolationSQL($level)
2925
    {
2926
        throw DBALException::notSupported(__METHOD__);
2927
    }
2928
2929
    /**
2930
     * Obtains DBMS specific SQL to be used to create datetime fields in
2931
     * statements like CREATE TABLE.
2932
     *
2933
     * @param array $fieldDeclaration
2934
     *
2935
     * @return string
2936
     *
2937
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2938
     */
2939
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
2940
    {
2941
        throw DBALException::notSupported(__METHOD__);
2942
    }
2943
2944
    /**
2945
     * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields.
2946
     *
2947
     * @param array $fieldDeclaration
2948
     *
2949
     * @return string
2950
     */
2951 15
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
2952
    {
2953 15
        return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
2954
    }
2955
2956
2957
    /**
2958
     * Obtains DBMS specific SQL to be used to create date fields in statements
2959
     * like CREATE TABLE.
2960
     *
2961
     * @param array $fieldDeclaration
2962
     *
2963
     * @return string
2964
     *
2965
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2966
     */
2967
    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...
2968
    {
2969
        throw DBALException::notSupported(__METHOD__);
2970
    }
2971
2972
    /**
2973
     * Obtains DBMS specific SQL to be used to create time fields in statements
2974
     * like CREATE TABLE.
2975
     *
2976
     * @param array $fieldDeclaration
2977
     *
2978
     * @return string
2979
     *
2980
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
2981
     */
2982
    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...
2983
    {
2984
        throw DBALException::notSupported(__METHOD__);
2985
    }
2986
2987
    /**
2988
     * @param array $fieldDeclaration
2989
     *
2990
     * @return string
2991
     */
2992 99
    public function getFloatDeclarationSQL(array $fieldDeclaration)
2993
    {
2994 99
        return 'DOUBLE PRECISION';
2995
    }
2996
2997
    /**
2998
     * Gets the default transaction isolation level of the platform.
2999
     *
3000
     * @return integer The default isolation level.
3001
     *
3002
     * @see Doctrine\DBAL\Connection\TRANSACTION_* constants.
3003
     */
3004
    public function getDefaultTransactionIsolationLevel()
3005
    {
3006
        return Connection::TRANSACTION_READ_COMMITTED;
3007
    }
3008
3009
    /* supports*() methods */
3010
3011
    /**
3012
     * Whether the platform supports sequences.
3013
     *
3014
     * @return boolean
3015
     */
3016 6
    public function supportsSequences()
3017
    {
3018 6
        return false;
3019
    }
3020
3021
    /**
3022
     * Whether the platform supports identity columns.
3023
     *
3024
     * Identity columns are columns that receive an auto-generated value from the
3025
     * database on insert of a row.
3026
     *
3027
     * @return boolean
3028
     */
3029 1
    public function supportsIdentityColumns()
3030
    {
3031 1
        return false;
3032
    }
3033
3034
    /**
3035
     * Whether the platform emulates identity columns through sequences.
3036
     *
3037
     * Some platforms that do not support identity columns natively
3038
     * but support sequences can emulate identity columns by using
3039
     * sequences.
3040
     *
3041
     * @return boolean
3042
     */
3043 12
    public function usesSequenceEmulatedIdentityColumns()
3044
    {
3045 12
        return false;
3046
    }
3047
3048
    /**
3049
     * Returns the name of the sequence for a particular identity column in a particular table.
3050
     *
3051
     * @param string $tableName  The name of the table to return the sequence name for.
3052
     * @param string $columnName The name of the identity column in the table to return the sequence name for.
3053
     *
3054
     * @return string
3055
     *
3056
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3057
     *
3058
     * @see    usesSequenceEmulatedIdentityColumns
3059
     */
3060 11
    public function getIdentitySequenceName($tableName, $columnName)
3061
    {
3062 11
        throw DBALException::notSupported(__METHOD__);
3063
    }
3064
3065
    /**
3066
     * Whether the platform supports indexes.
3067
     *
3068
     * @return boolean
3069
     */
3070 4
    public function supportsIndexes()
3071
    {
3072 4
        return true;
3073
    }
3074
3075
    /**
3076
     * Whether the platform supports partial indexes.
3077
     *
3078
     * @return boolean
3079
     */
3080 126
    public function supportsPartialIndexes()
3081
    {
3082 126
        return false;
3083
    }
3084
3085
    /**
3086
     * Whether the platform supports altering tables.
3087
     *
3088
     * @return boolean
3089
     */
3090 5
    public function supportsAlterTable()
3091
    {
3092 5
        return true;
3093
    }
3094
3095
    /**
3096
     * Whether the platform supports transactions.
3097
     *
3098
     * @return boolean
3099
     */
3100 4
    public function supportsTransactions()
3101
    {
3102 4
        return true;
3103
    }
3104
3105
    /**
3106
     * Whether the platform supports savepoints.
3107
     *
3108
     * @return boolean
3109
     */
3110 20
    public function supportsSavepoints()
3111
    {
3112 20
        return true;
3113
    }
3114
3115
    /**
3116
     * Whether the platform supports releasing savepoints.
3117
     *
3118
     * @return boolean
3119
     */
3120 5
    public function supportsReleaseSavepoints()
3121
    {
3122 5
        return $this->supportsSavepoints();
3123
    }
3124
3125
    /**
3126
     * Whether the platform supports primary key constraints.
3127
     *
3128
     * @return boolean
3129
     */
3130 4
    public function supportsPrimaryConstraints()
3131
    {
3132 4
        return true;
3133
    }
3134
3135
    /**
3136
     * Whether the platform supports foreign key constraints.
3137
     *
3138
     * @return boolean
3139
     */
3140 370
    public function supportsForeignKeyConstraints()
3141
    {
3142 370
        return true;
3143
    }
3144
3145
    /**
3146
     * Whether this platform supports onUpdate in foreign key constraints.
3147
     *
3148
     * @return boolean
3149
     */
3150 89
    public function supportsForeignKeyOnUpdate()
3151
    {
3152 89
        return ($this->supportsForeignKeyConstraints() && true);
3153
    }
3154
3155
    /**
3156
     * Whether the platform supports database schemas.
3157
     *
3158
     * @return boolean
3159
     */
3160 10
    public function supportsSchemas()
3161
    {
3162 10
        return false;
3163
    }
3164
3165
    /**
3166
     * Whether this platform can emulate schemas.
3167
     *
3168
     * Platforms that either support or emulate schemas don't automatically
3169
     * filter a schema for the namespaced elements in {@link
3170
     * AbstractManager#createSchema}.
3171
     *
3172
     * @return boolean
3173
     */
3174 4
    public function canEmulateSchemas()
3175
    {
3176 4
        return false;
3177
    }
3178
3179
    /**
3180
     * Returns the default schema name.
3181
     *
3182
     * @return string
3183
     *
3184
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3185
     */
3186
    public function getDefaultSchemaName()
3187
    {
3188
        throw DBALException::notSupported(__METHOD__);
3189
    }
3190
3191
    /**
3192
     * Whether this platform supports create database.
3193
     *
3194
     * Some databases don't allow to create and drop databases at all or only with certain tools.
3195
     *
3196
     * @return boolean
3197
     */
3198 4
    public function supportsCreateDropDatabase()
3199
    {
3200 4
        return true;
3201
    }
3202
3203
    /**
3204
     * Whether the platform supports getting the affected rows of a recent update/delete type query.
3205
     *
3206
     * @return boolean
3207
     */
3208 4
    public function supportsGettingAffectedRows()
3209
    {
3210 4
        return true;
3211
    }
3212
3213
    /**
3214
     * Whether this platform support to add inline column comments as postfix.
3215
     *
3216
     * @return boolean
3217
     */
3218 161
    public function supportsInlineColumnComments()
3219
    {
3220 161
        return false;
3221
    }
3222
3223
    /**
3224
     * Whether this platform support the proprietary syntax "COMMENT ON asset".
3225
     *
3226
     * @return boolean
3227
     */
3228 229
    public function supportsCommentOnStatement()
3229
    {
3230 229
        return false;
3231
    }
3232
3233
    /**
3234
     * Does this platform have native guid type.
3235
     *
3236
     * @return boolean
3237
     */
3238 249
    public function hasNativeGuidType()
3239
    {
3240 249
        return false;
3241
    }
3242
3243
    /**
3244
     * Does this platform have native JSON type.
3245
     *
3246
     * @return boolean
3247
     */
3248 616
    public function hasNativeJsonType()
3249
    {
3250 616
        return false;
3251
    }
3252
3253
    /**
3254
     * @deprecated
3255
     * @todo Remove in 3.0
3256
     */
3257
    public function getIdentityColumnNullInsertSQL()
3258
    {
3259
        return "";
3260
    }
3261
3262
    /**
3263
     * Whether this platform supports views.
3264
     *
3265
     * @return boolean
3266
     */
3267 1
    public function supportsViews()
3268
    {
3269 1
        return true;
3270
    }
3271
3272
    /**
3273
     * Does this platform support column collation?
3274
     *
3275
     * @return boolean
3276
     */
3277
    public function supportsColumnCollation()
3278
    {
3279
        return false;
3280
    }
3281
3282
    /**
3283
     * Gets the format string, as accepted by the date() function, that describes
3284
     * the format of a stored datetime value of this platform.
3285
     *
3286
     * @return string The format string.
3287
     */
3288 18
    public function getDateTimeFormatString()
3289
    {
3290 18
        return 'Y-m-d H:i:s';
3291
    }
3292
3293
    /**
3294
     * Gets the format string, as accepted by the date() function, that describes
3295
     * the format of a stored datetime with timezone value of this platform.
3296
     *
3297
     * @return string The format string.
3298
     */
3299 8
    public function getDateTimeTzFormatString()
3300
    {
3301 8
        return 'Y-m-d H:i:s';
3302
    }
3303
3304
    /**
3305
     * Gets the format string, as accepted by the date() function, that describes
3306
     * the format of a stored date value of this platform.
3307
     *
3308
     * @return string The format string.
3309
     */
3310 7
    public function getDateFormatString()
3311
    {
3312 7
        return 'Y-m-d';
3313
    }
3314
3315
    /**
3316
     * Gets the format string, as accepted by the date() function, that describes
3317
     * the format of a stored time value of this platform.
3318
     *
3319
     * @return string The format string.
3320
     */
3321 6
    public function getTimeFormatString()
3322
    {
3323 6
        return 'H:i:s';
3324
    }
3325
3326
    /**
3327
     * Adds an driver-specific LIMIT clause to the query.
3328
     *
3329
     * @param string       $query
3330
     * @param integer|null $limit
3331
     * @param integer|null $offset
3332
     *
3333
     * @return string
3334
     *
3335
     * @throws DBALException
3336
     */
3337 113
    final public function modifyLimitQuery($query, $limit, $offset = null)
3338
    {
3339 113
        if ($limit !== null) {
3340 108
            $limit = (int) $limit;
3341
        }
3342
3343 113
        if ($offset !== null) {
3344 44
            $offset = (int) $offset;
3345
3346 44
            if ($offset < 0) {
3347
                throw new DBALException("LIMIT argument offset=$offset is not valid");
3348
            }
3349 44
            if ($offset > 0 && ! $this->supportsLimitOffset()) {
3350
                throw new DBALException(sprintf("Platform %s does not support offset values in limit queries.", $this->getName()));
3351
            }
3352
        }
3353
3354 113
        return $this->doModifyLimitQuery($query, $limit, $offset);
3355
    }
3356
3357
    /**
3358
     * Adds an driver-specific LIMIT clause to the query.
3359
     *
3360
     * @param string       $query
3361
     * @param integer|null $limit
3362
     * @param integer|null $offset
3363
     *
3364
     * @return string
3365
     */
3366 17
    protected function doModifyLimitQuery($query, $limit, $offset)
3367
    {
3368 17
        if ($limit !== null) {
3369 17
            $query .= ' LIMIT ' . $limit;
3370
        }
3371
3372 17
        if ($offset !== null) {
3373 12
            $query .= ' OFFSET ' . $offset;
3374
        }
3375
3376 17
        return $query;
3377
    }
3378
3379
    /**
3380
     * Whether the database platform support offsets in modify limit clauses.
3381
     *
3382
     * @return boolean
3383
     */
3384 17
    public function supportsLimitOffset()
3385
    {
3386 17
        return true;
3387
    }
3388
3389
    /**
3390
     * Gets the character casing of a column in an SQL result set of this platform.
3391
     *
3392
     * @param string $column The column name for which to get the correct character casing.
3393
     *
3394
     * @return string The column name in the character casing used in SQL result sets.
3395
     */
3396
    public function getSQLResultCasing($column)
3397
    {
3398
        return $column;
3399
    }
3400
3401
    /**
3402
     * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
3403
     * by restrictions of the platform, like a maximum length.
3404
     *
3405
     * @param string $schemaElementName
3406
     *
3407
     * @return string
3408
     */
3409
    public function fixSchemaElementName($schemaElementName)
3410
    {
3411
        return $schemaElementName;
3412
    }
3413
3414
    /**
3415
     * Maximum length of any given database identifier, like tables or column names.
3416
     *
3417
     * @return integer
3418
     */
3419 13
    public function getMaxIdentifierLength()
3420
    {
3421 13
        return 63;
3422
    }
3423
3424
    /**
3425
     * Returns the insert SQL for an empty insert statement.
3426
     *
3427
     * @param string $tableName
3428
     * @param string $identifierColumnName
3429
     *
3430
     * @return string
3431
     */
3432 1
    public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
3433
    {
3434 1
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
3435
    }
3436
3437
    /**
3438
     * Generates a Truncate Table SQL statement for a given table.
3439
     *
3440
     * Cascade is not supported on many platforms but would optionally cascade the truncate by
3441
     * following the foreign keys.
3442
     *
3443
     * @param string  $tableName
3444
     * @param boolean $cascade
3445
     *
3446
     * @return string
3447
     */
3448 2
    public function getTruncateTableSQL($tableName, $cascade = false)
3449
    {
3450 2
        $tableIdentifier = new Identifier($tableName);
3451
3452 2
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3453
    }
3454
3455
    /**
3456
     * This is for test reasons, many vendors have special requirements for dummy statements.
3457
     *
3458
     * @return string
3459
     */
3460 6
    public function getDummySelectSQL()
3461
    {
3462 6
        return 'SELECT 1';
3463
    }
3464
3465
    /**
3466
     * Returns the SQL to create a new savepoint.
3467
     *
3468
     * @param string $savepoint
3469
     *
3470
     * @return string
3471
     */
3472 1
    public function createSavePoint($savepoint)
3473
    {
3474 1
        return 'SAVEPOINT ' . $savepoint;
3475
    }
3476
3477
    /**
3478
     * Returns the SQL to release a savepoint.
3479
     *
3480
     * @param string $savepoint
3481
     *
3482
     * @return string
3483
     */
3484 1
    public function releaseSavePoint($savepoint)
3485
    {
3486 1
        return 'RELEASE SAVEPOINT ' . $savepoint;
3487
    }
3488
3489
    /**
3490
     * Returns the SQL to rollback a savepoint.
3491
     *
3492
     * @param string $savepoint
3493
     *
3494
     * @return string
3495
     */
3496 1
    public function rollbackSavePoint($savepoint)
3497
    {
3498 1
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3499
    }
3500
3501
    /**
3502
     * Returns the keyword list instance of this platform.
3503
     *
3504
     * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList
3505
     *
3506
     * @throws \Doctrine\DBAL\DBALException If no keyword list is specified.
3507
     */
3508 954
    final public function getReservedKeywordsList()
3509
    {
3510
        // Check for an existing instantiation of the keywords class.
3511 954
        if ($this->_keywords) {
3512 893
            return $this->_keywords;
3513
        }
3514
3515 833
        $class = $this->getReservedKeywordsClass();
3516 833
        $keywords = new $class;
3517 833
        if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) {
3518
            throw DBALException::notSupported(__METHOD__);
3519
        }
3520
3521
        // Store the instance so it doesn't need to be generated on every request.
3522 833
        $this->_keywords = $keywords;
3523
3524 833
        return $keywords;
3525
    }
3526
3527
    /**
3528
     * Returns the class name of the reserved keywords list.
3529
     *
3530
     * @return string
3531
     *
3532
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
3533
     */
3534
    protected function getReservedKeywordsClass()
3535
    {
3536
        throw DBALException::notSupported(__METHOD__);
3537
    }
3538
3539
    /**
3540
     * Quotes a literal string.
3541
     * This method is NOT meant to fix SQL injections!
3542
     * It is only meant to escape this platform's string literal
3543
     * quote character inside the given literal string.
3544
     *
3545
     * @param string $str The literal string to be quoted.
3546
     *
3547
     * @return string The quoted literal string.
3548
     */
3549 293
    public function quoteStringLiteral($str)
3550
    {
3551 293
        $c = $this->getStringLiteralQuoteCharacter();
3552
3553 293
        return $c . str_replace($c, $c . $c, $str) . $c;
3554
    }
3555
3556
    /**
3557
     * Gets the character used for string literal quoting.
3558
     *
3559
     * @return string
3560
     */
3561 309
    public function getStringLiteralQuoteCharacter()
3562
    {
3563 309
        return "'";
3564
    }
3565
}
3566