Completed
Pull Request — master (#2823)
by Mike
10:27
created

AbstractPlatform   F

Complexity

Total Complexity 382

Size/Duplication

Total Lines 3502
Duplicated Lines 7.02 %

Coupling/Cohesion

Components 6
Dependencies 18

Test Coverage

Coverage 76.82%

Importance

Changes 0
Metric Value
wmc 382
lcom 6
cbo 18
dl 246
loc 3502
ccs 613
cts 798
cp 0.7682
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 ?
getClobTypeDeclarationSQL() 0 1 ?
getBlobTypeDeclarationSQL() 0 1 ?
getName() 0 1 ?
A initializeAllDoctrineTypeMappings() 6 11 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
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
B getCreateConstraintSQL() 0 31 6
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
C getDefaultValueDeclarationSQL() 6 23 12
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\DBAL\DBALException;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\Schema\Identifier;
25
use Doctrine\DBAL\Types;
26
use Doctrine\DBAL\Schema\Constraint;
27
use Doctrine\DBAL\Schema\Sequence;
28
use Doctrine\DBAL\Schema\Table;
29
use Doctrine\DBAL\Schema\Index;
30
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
31
use Doctrine\DBAL\Schema\TableDiff;
32
use Doctrine\DBAL\Schema\Column;
33
use Doctrine\DBAL\Schema\ColumnDiff;
34
use Doctrine\DBAL\Types\Type;
35
use Doctrine\DBAL\Events;
36
use Doctrine\Common\EventManager;
37
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
38
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
39
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
40
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
41
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
42
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
43
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
44
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
45
46
/**
47
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
48
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
49
 * They are a passive source of information.
50
 *
51
 * @link   www.doctrine-project.org
52
 * @since  2.0
53
 * @author Guilherme Blanco <[email protected]>
54
 * @author Jonathan Wage <[email protected]>
55
 * @author Roman Borschel <[email protected]>
56
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
57
 * @author Benjamin Eberlei <[email protected]>
58
 * @todo   Remove any unnecessary methods.
59
 */
60
abstract class AbstractPlatform
61
{
62
    /**
63
     * @var integer
64
     */
65
    const CREATE_INDEXES = 1;
66
67
    /**
68
     * @var integer
69
     */
70
    const CREATE_FOREIGNKEYS = 2;
71
72
    /**
73
     * @var string
74
     */
75
    const DATE_INTERVAL_UNIT_SECOND = 'SECOND';
76
77
    /**
78
     * @var string
79
     */
80
    const DATE_INTERVAL_UNIT_MINUTE = 'MINUTE';
81
82
    /**
83
     * @var string
84
     */
85
    const DATE_INTERVAL_UNIT_HOUR = 'HOUR';
86
87
    /**
88
     * @var string
89
     */
90
    const DATE_INTERVAL_UNIT_DAY = 'DAY';
91
92
    /**
93
     * @var string
94
     */
95
    const DATE_INTERVAL_UNIT_WEEK = 'WEEK';
96
97
    /**
98
     * @var string
99
     */
100
    const DATE_INTERVAL_UNIT_MONTH = 'MONTH';
101
102
    /**
103
     * @var string
104
     */
105
    const DATE_INTERVAL_UNIT_QUARTER = 'QUARTER';
106
107
    /**
108
     * @var string
109
     */
110
    const DATE_INTERVAL_UNIT_YEAR = 'YEAR';
111
112
    /**
113
     * @var integer
114
     */
115
    const TRIM_UNSPECIFIED = 0;
116
117
    /**
118
     * @var integer
119
     */
120
    const TRIM_LEADING = 1;
121
122
    /**
123
     * @var integer
124
     */
125
    const TRIM_TRAILING = 2;
126
127
    /**
128
     * @var integer
129
     */
130
    const TRIM_BOTH = 3;
131
132
    /**
133
     * @var array|null
134
     */
135
    protected $doctrineTypeMapping = null;
136
137
    /**
138
     * Contains a list of all columns that should generate parseable column comments for type-detection
139
     * in reverse engineering scenarios.
140
     *
141
     * @var array|null
142
     */
143
    protected $doctrineTypeComments = null;
144
145
    /**
146
     * @var \Doctrine\Common\EventManager
147
     */
148
    protected $_eventManager;
149
150
    /**
151
     * Holds the KeywordList instance for the current platform.
152
     *
153
     * @var \Doctrine\DBAL\Platforms\Keywords\KeywordList
154
     */
155
    protected $_keywords;
156
157
    /**
158
     * Constructor.
159
     */
160 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 80
    public function setEventManager(EventManager $eventManager)
170
    {
171 80
        $this->_eventManager = $eventManager;
172 80
    }
173
174
    /**
175
     * Gets the EventManager used by the Platform.
176
     *
177
     * @return \Doctrine\Common\EventManager
178
     */
179 43
    public function getEventManager()
180
    {
181 43
        return $this->_eventManager;
182
    }
183
184
    /**
185
     * Returns the SQL snippet that declares a boolean column.
186
     *
187
     * @param array $columnDef
188
     *
189
     * @return string
190
     */
191
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
192
193
    /**
194
     * Returns the SQL snippet that declares a 4 byte integer column.
195
     *
196
     * @param array $columnDef
197
     *
198
     * @return string
199
     */
200
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
201
202
    /**
203
     * Returns the SQL snippet that declares an 8 byte integer column.
204
     *
205
     * @param array $columnDef
206
     *
207
     * @return string
208
     */
209
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
210
211
    /**
212
     * Returns the SQL snippet that declares a 2 byte integer column.
213
     *
214
     * @param array $columnDef
215
     *
216
     * @return string
217
     */
218
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
219
220
    /**
221
     * Returns the SQL snippet that declares common properties of an integer column.
222
     *
223
     * @param array $columnDef
224
     *
225
     * @return string
226
     */
227
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
228
229
    /**
230
     * Lazy load Doctrine Type Mappings.
231
     *
232
     * @return void
233
     */
234
    abstract protected function initializeDoctrineTypeMappings();
235
236
    /**
237
     * Initializes Doctrine Type Mappings with the platform defaults
238
     * and with all additional type mappings.
239
     *
240
     * @return void
241
     */
242 87
    private function initializeAllDoctrineTypeMappings()
243
    {
244 87
        $this->initializeDoctrineTypeMappings();
245
246 87 View Code Duplication
        foreach (Type::getTypesMap() as $typeName => $className) {
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...
247 87
            $type = Type::getType($typeName);
248 87
            foreach ($type->getMappedDatabaseTypes($this) as $dbType) {
249 87
                $this->doctrineTypeMapping[$dbType] = $typeName;
250
            }
251
        }
252 87
    }
253
254
    /**
255
     * Returns the SQL snippet used to declare a VARCHAR column type.
256
     *
257
     * @param array $field
258
     *
259
     * @return string
260
     */
261 304
    public function getVarcharTypeDeclarationSQL(array $field)
262
    {
263 304
        if ( !isset($field['length'])) {
264 73
            $field['length'] = $this->getVarcharDefaultLength();
265
        }
266
267 304
        $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
268
269 304
        if ($field['length'] > $this->getVarcharMaxLength()) {
270
            return $this->getClobTypeDeclarationSQL($field);
271
        }
272
273 304
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
274
    }
275
276
    /**
277
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
278
     *
279
     * @param array $field The column definition.
280
     *
281
     * @return string
282
     */
283 20
    public function getBinaryTypeDeclarationSQL(array $field)
284
    {
285 20
        if ( ! isset($field['length'])) {
286 17
            $field['length'] = $this->getBinaryDefaultLength();
287
        }
288
289 20
        $fixed = isset($field['fixed']) ? $field['fixed'] : false;
290
291 20
        if ($field['length'] > $this->getBinaryMaxLength()) {
292 19
            return $this->getBlobTypeDeclarationSQL($field);
293
        }
294
295 17
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
296
    }
297
298
    /**
299
     * Returns the SQL snippet to declare a GUID/UUID field.
300
     *
301
     * By default this maps directly to a CHAR(36) and only maps to more
302
     * special datatypes when the underlying databases support this datatype.
303
     *
304
     * @param array $field
305
     *
306
     * @return string
307
     */
308 5
    public function getGuidTypeDeclarationSQL(array $field)
309
    {
310 5
        $field['length'] = 36;
311 5
        $field['fixed']  = true;
312
313 5
        return $this->getVarcharTypeDeclarationSQL($field);
314
    }
315
316
    /**
317
     * Returns the SQL snippet to declare a JSON field.
318
     *
319
     * By default this maps directly to a CLOB and only maps to more
320
     * special datatypes when the underlying databases support this datatype.
321
     *
322
     * @param array $field
323
     *
324
     * @return string
325
     */
326 28
    public function getJsonTypeDeclarationSQL(array $field)
327
    {
328 28
        return $this->getClobTypeDeclarationSQL($field);
329
    }
330
331
    /**
332
     * @param integer $length
333
     * @param boolean $fixed
334
     *
335
     * @return string
336
     *
337
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
338
     */
339
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
340
    {
341
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
342
    }
343
344
    /**
345
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
346
     *
347
     * @param integer $length The length of the column.
348
     * @param boolean $fixed  Whether the column length is fixed.
349
     *
350
     * @return string
351
     *
352
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
353
     */
354
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
355
    {
356
        throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.');
357
    }
358
359
    /**
360
     * Returns the SQL snippet used to declare a CLOB column type.
361
     *
362
     * @param array $field
363
     *
364
     * @return string
365
     */
366
    abstract public function getClobTypeDeclarationSQL(array $field);
367
368
    /**
369
     * Returns the SQL Snippet used to declare a BLOB column type.
370
     *
371
     * @param array $field
372
     *
373
     * @return string
374
     */
375
    abstract public function getBlobTypeDeclarationSQL(array $field);
376
377
    /**
378
     * Gets the name of the platform.
379
     *
380
     * @return string
381
     */
382
    abstract public function getName();
383
384
    /**
385
     * Registers a doctrine type to be used in conjunction with a column type of this platform.
386
     *
387
     * @param string $dbType
388
     * @param string $doctrineType
389
     *
390
     * @throws \Doctrine\DBAL\DBALException If the type is not found.
391
     */
392 49
    public function registerDoctrineTypeMapping($dbType, $doctrineType)
393
    {
394 49
        if ($this->doctrineTypeMapping === null) {
395 49
            $this->initializeAllDoctrineTypeMappings();
396
        }
397
398 49
        if (!Types\Type::hasType($doctrineType)) {
399 16
            throw DBALException::typeNotFound($doctrineType);
400
        }
401
402 33
        $dbType = strtolower($dbType);
403 33
        $this->doctrineTypeMapping[$dbType] = $doctrineType;
404
405 33
        $doctrineType = Type::getType($doctrineType);
406
407 33
        if ($doctrineType->requiresSQLCommentHint($this)) {
408 16
            $this->markDoctrineTypeCommented($doctrineType);
409
        }
410 33
    }
411
412
    /**
413
     * Gets the Doctrine type that is mapped for the given database column type.
414
     *
415
     * @param string $dbType
416
     *
417
     * @return string
418
     *
419
     * @throws \Doctrine\DBAL\DBALException
420
     */
421 91
    public function getDoctrineTypeMapping($dbType)
422
    {
423 91
        if ($this->doctrineTypeMapping === null) {
424 19
            $this->initializeAllDoctrineTypeMappings();
425
        }
426
427 91
        $dbType = strtolower($dbType);
428
429 91
        if (!isset($this->doctrineTypeMapping[$dbType])) {
430 16
            throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it.");
431
        }
432
433 75
        return $this->doctrineTypeMapping[$dbType];
434
    }
435
436
    /**
437
     * Checks if a database type is currently supported by this platform.
438
     *
439
     * @param string $dbType
440
     *
441
     * @return boolean
442
     */
443 20
    public function hasDoctrineTypeMappingFor($dbType)
444
    {
445 20
        if ($this->doctrineTypeMapping === null) {
446 19
            $this->initializeAllDoctrineTypeMappings();
447
        }
448
449 20
        $dbType = strtolower($dbType);
450
451 20
        return isset($this->doctrineTypeMapping[$dbType]);
452
    }
453
454
    /**
455
     * Initializes the Doctrine Type comments instance variable for in_array() checks.
456
     *
457
     * @return void
458
     */
459 748
    protected function initializeCommentedDoctrineTypes()
460
    {
461 748
        $this->doctrineTypeComments = [];
462
463 748
        foreach (Type::getTypesMap() as $typeName => $className) {
464 748
            $type = Type::getType($typeName);
465
466 748
            if ($type->requiresSQLCommentHint($this)) {
467 748
                $this->doctrineTypeComments[] = $typeName;
468
            }
469
        }
470 748
    }
471
472
    /**
473
     * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type?
474
     *
475
     * @param \Doctrine\DBAL\Types\Type $doctrineType
476
     *
477
     * @return boolean
478
     */
479 860
    public function isCommentedDoctrineType(Type $doctrineType)
480
    {
481 860
        if ($this->doctrineTypeComments === null) {
482 732
            $this->initializeCommentedDoctrineTypes();
483
        }
484
485 860
        return in_array($doctrineType->getName(), $this->doctrineTypeComments);
486
    }
487
488
    /**
489
     * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements.
490
     *
491
     * @param string|\Doctrine\DBAL\Types\Type $doctrineType
492
     *
493
     * @return void
494
     */
495 16
    public function markDoctrineTypeCommented($doctrineType)
496
    {
497 16
        if ($this->doctrineTypeComments === null) {
498 16
            $this->initializeCommentedDoctrineTypes();
499
        }
500
501 16
        $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
502 16
    }
503
504
    /**
505
     * Gets the comment to append to a column comment that helps parsing this type in reverse engineering.
506
     *
507
     * @param \Doctrine\DBAL\Types\Type $doctrineType
508
     *
509
     * @return string
510
     */
511 38
    public function getDoctrineTypeComment(Type $doctrineType)
512
    {
513 38
        return '(DC2Type:' . $doctrineType->getName() . ')';
514
    }
515
516
    /**
517
     * Gets the comment of a passed column modified by potential doctrine type comment hints.
518
     *
519
     * @param \Doctrine\DBAL\Schema\Column $column
520
     *
521
     * @return string
522
     */
523 445
    protected function getColumnComment(Column $column)
524
    {
525 445
        $comment = $column->getComment();
526
527 445
        if ($this->isCommentedDoctrineType($column->getType())) {
528 38
            $comment .= $this->getDoctrineTypeComment($column->getType());
529
        }
530
531 445
        return $comment;
532
    }
533
534
    /**
535
     * Gets the character used for identifier quoting.
536
     *
537
     * @return string
538
     */
539 274
    public function getIdentifierQuoteCharacter()
540
    {
541 274
        return '"';
542
    }
543
544
    /**
545
     * Gets the string portion that starts an SQL comment.
546
     *
547
     * @return string
548
     */
549
    public function getSqlCommentStartString()
550
    {
551
        return "--";
552
    }
553
554
    /**
555
     * Gets the string portion that ends an SQL comment.
556
     *
557
     * @return string
558
     */
559
    public function getSqlCommentEndString()
560
    {
561
        return "\n";
562
    }
563
564
    /**
565
     * Gets the maximum length of a varchar field.
566
     *
567
     * @return integer
568
     */
569 178
    public function getVarcharMaxLength()
570
    {
571 178
        return 4000;
572
    }
573
574
    /**
575
     * Gets the default length of a varchar field.
576
     *
577
     * @return integer
578
     */
579 61
    public function getVarcharDefaultLength()
580
    {
581 61
        return 255;
582
    }
583
584
    /**
585
     * Gets the maximum length of a binary field.
586
     *
587
     * @return integer
588
     */
589
    public function getBinaryMaxLength()
590
    {
591
        return 4000;
592
    }
593
594
    /**
595
     * Gets the default length of a binary field.
596
     *
597
     * @return integer
598
     */
599 12
    public function getBinaryDefaultLength()
600
    {
601 12
        return 255;
602
    }
603
604
    /**
605
     * Gets all SQL wildcard characters of the platform.
606
     *
607
     * @return array
608
     */
609
    public function getWildcards()
610
    {
611
        return ['%', '_'];
612
    }
613
614
    /**
615
     * Returns the regular expression operator.
616
     *
617
     * @return string
618
     *
619
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
620
     */
621 5
    public function getRegexpExpression()
622
    {
623 5
        throw DBALException::notSupported(__METHOD__);
624
    }
625
626
    /**
627
     * Returns the global unique identifier expression.
628
     *
629
     * @return string
630
     *
631
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
632
     */
633
    public function getGuidExpression()
634
    {
635
        throw DBALException::notSupported(__METHOD__);
636
    }
637
638
    /**
639
     * Returns the SQL snippet to get the average value of a column.
640
     *
641
     * @param string $column The column to use.
642
     *
643
     * @return string Generated SQL including an AVG aggregate function.
644
     */
645
    public function getAvgExpression($column)
646
    {
647
        return 'AVG(' . $column . ')';
648
    }
649
650
    /**
651
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
652
     *
653
     * If a '*' is used instead of a column the number of selected rows is returned.
654
     *
655
     * @param string|integer $column The column to use.
656
     *
657
     * @return string Generated SQL including a COUNT aggregate function.
658
     */
659
    public function getCountExpression($column)
660
    {
661
        return 'COUNT(' . $column . ')';
662
    }
663
664
    /**
665
     * Returns the SQL snippet to get the highest value of a column.
666
     *
667
     * @param string $column The column to use.
668
     *
669
     * @return string Generated SQL including a MAX aggregate function.
670
     */
671
    public function getMaxExpression($column)
672
    {
673
        return 'MAX(' . $column . ')';
674
    }
675
676
    /**
677
     * Returns the SQL snippet to get the lowest value of a column.
678
     *
679
     * @param string $column The column to use.
680
     *
681
     * @return string Generated SQL including a MIN aggregate function.
682
     */
683
    public function getMinExpression($column)
684
    {
685
        return 'MIN(' . $column . ')';
686
    }
687
688
    /**
689
     * Returns the SQL snippet to get the total sum of a column.
690
     *
691
     * @param string $column The column to use.
692
     *
693
     * @return string Generated SQL including a SUM aggregate function.
694
     */
695
    public function getSumExpression($column)
696
    {
697
        return 'SUM(' . $column . ')';
698
    }
699
700
    // scalar functions
701
702
    /**
703
     * Returns the SQL snippet to get the md5 sum of a field.
704
     *
705
     * Note: Not SQL92, but common functionality.
706
     *
707
     * @param string $column
708
     *
709
     * @return string
710
     */
711
    public function getMd5Expression($column)
712
    {
713
        return 'MD5(' . $column . ')';
714
    }
715
716
    /**
717
     * Returns the SQL snippet to get the length of a text field.
718
     *
719
     * @param string $column
720
     *
721
     * @return string
722
     */
723
    public function getLengthExpression($column)
724
    {
725
        return 'LENGTH(' . $column . ')';
726
    }
727
728
    /**
729
     * Returns the SQL snippet to get the squared value of a column.
730
     *
731
     * @param string $column The column to use.
732
     *
733
     * @return string Generated SQL including an SQRT aggregate function.
734
     */
735
    public function getSqrtExpression($column)
736
    {
737
        return 'SQRT(' . $column . ')';
738
    }
739
740
    /**
741
     * Returns the SQL snippet to round a numeric field to the number of decimals specified.
742
     *
743
     * @param string  $column
744
     * @param integer $decimals
745
     *
746
     * @return string
747
     */
748
    public function getRoundExpression($column, $decimals = 0)
749
    {
750
        return 'ROUND(' . $column . ', ' . $decimals . ')';
751
    }
752
753
    /**
754
     * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
755
     *
756
     * @param string $expression1
757
     * @param string $expression2
758
     *
759
     * @return string
760
     */
761
    public function getModExpression($expression1, $expression2)
762
    {
763
        return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
764
    }
765
766
    /**
767
     * Returns the SQL snippet to trim a string.
768
     *
769
     * @param string         $str  The expression to apply the trim to.
770
     * @param integer        $pos  The position of the trim (leading/trailing/both).
771
     * @param string|boolean $char The char to trim, has to be quoted already. Defaults to space.
772
     *
773
     * @return string
774
     */
775
    public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
776
    {
777
        $expression = '';
778
779
        switch ($pos) {
780
            case self::TRIM_LEADING:
781
                $expression = 'LEADING ';
782
                break;
783
784
            case self::TRIM_TRAILING:
785
                $expression = 'TRAILING ';
786
                break;
787
788
            case self::TRIM_BOTH:
789
                $expression = 'BOTH ';
790
                break;
791
        }
792
793
        if (false !== $char) {
794
            $expression .= $char . ' ';
795
        }
796
797
        if ($pos || false !== $char) {
798
            $expression .= 'FROM ';
799
        }
800
801
        return 'TRIM(' . $expression . $str . ')';
802
    }
803
804
    /**
805
     * Returns the SQL snippet to trim trailing space characters from the expression.
806
     *
807
     * @param string $str Literal string or column name.
808
     *
809
     * @return string
810
     */
811 4
    public function getRtrimExpression($str)
812
    {
813 4
        return 'RTRIM(' . $str . ')';
814
    }
815
816
    /**
817
     * Returns the SQL snippet to trim leading space characters from the expression.
818
     *
819
     * @param string $str Literal string or column name.
820
     *
821
     * @return string
822
     */
823 4
    public function getLtrimExpression($str)
824
    {
825 4
        return 'LTRIM(' . $str . ')';
826
    }
827
828
    /**
829
     * Returns the SQL snippet to change all characters from the expression to uppercase,
830
     * according to the current character set mapping.
831
     *
832
     * @param string $str Literal string or column name.
833
     *
834
     * @return string
835
     */
836
    public function getUpperExpression($str)
837
    {
838
        return 'UPPER(' . $str . ')';
839
    }
840
841
    /**
842
     * Returns the SQL snippet to change all characters from the expression to lowercase,
843
     * according to the current character set mapping.
844
     *
845
     * @param string $str Literal string or column name.
846
     *
847
     * @return string
848
     */
849
    public function getLowerExpression($str)
850
    {
851
        return 'LOWER(' . $str . ')';
852
    }
853
854
    /**
855
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
856
     *
857
     * @param string          $str      Literal string.
858
     * @param string          $substr   Literal string to find.
859
     * @param integer|boolean $startPos Position to start at, beginning of string by default.
860
     *
861
     * @return string
862
     *
863
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
864
     */
865
    public function getLocateExpression($str, $substr, $startPos = false)
866
    {
867
        throw DBALException::notSupported(__METHOD__);
868
    }
869
870
    /**
871
     * Returns the SQL snippet to get the current system date.
872
     *
873
     * @return string
874
     */
875
    public function getNowExpression()
876
    {
877
        return 'NOW()';
878
    }
879
880
    /**
881
     * Returns a SQL snippet to get a substring inside an SQL statement.
882
     *
883
     * Note: Not SQL92, but common functionality.
884
     *
885
     * SQLite only supports the 2 parameter variant of this function.
886
     *
887
     * @param string       $value  An sql string literal or column name/alias.
888
     * @param integer      $from   Where to start the substring portion.
889
     * @param integer|null $length The substring portion length.
890
     *
891
     * @return string
892
     */
893 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...
894
    {
895
        if ($length === null) {
896
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
897
        }
898
899
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
900
    }
901
902
    /**
903
     * Returns a SQL snippet to concatenate the given expressions.
904
     *
905
     * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
906
     *
907
     * @return string
908
     */
909 5
    public function getConcatExpression()
910
    {
911 5
        return join(' || ', func_get_args());
912
    }
913
914
    /**
915
     * Returns the SQL for a logical not.
916
     *
917
     * Example:
918
     * <code>
919
     * $q = new Doctrine_Query();
920
     * $e = $q->expr;
921
     * $q->select('*')->from('table')
922
     *   ->where($e->eq('id', $e->not('null'));
923
     * </code>
924
     *
925
     * @param string $expression
926
     *
927
     * @return string The logical expression.
928
     */
929
    public function getNotExpression($expression)
930
    {
931
        return 'NOT(' . $expression . ')';
932
    }
933
934
    /**
935
     * Returns the SQL that checks if an expression is null.
936
     *
937
     * @param string $expression The expression that should be compared to null.
938
     *
939
     * @return string The logical expression.
940
     */
941 4
    public function getIsNullExpression($expression)
942
    {
943 4
        return $expression . ' IS NULL';
944
    }
945
946
    /**
947
     * Returns the SQL that checks if an expression is not null.
948
     *
949
     * @param string $expression The expression that should be compared to null.
950
     *
951
     * @return string The logical expression.
952
     */
953
    public function getIsNotNullExpression($expression)
954
    {
955
        return $expression . ' IS NOT NULL';
956
    }
957
958
    /**
959
     * Returns the SQL that checks if an expression evaluates to a value between two values.
960
     *
961
     * The parameter $expression is checked if it is between $value1 and $value2.
962
     *
963
     * Note: There is a slight difference in the way BETWEEN works on some databases.
964
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
965
     * independence you should avoid using between().
966
     *
967
     * @param string $expression The value to compare to.
968
     * @param string $value1     The lower value to compare with.
969
     * @param string $value2     The higher value to compare with.
970
     *
971
     * @return string The logical expression.
972
     */
973
    public function getBetweenExpression($expression, $value1, $value2)
974
    {
975
        return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
976
    }
977
978
    /**
979
     * Returns the SQL to get the arccosine of a value.
980
     *
981
     * @param string $value
982
     *
983
     * @return string
984
     */
985
    public function getAcosExpression($value)
986
    {
987
        return 'ACOS(' . $value . ')';
988
    }
989
990
    /**
991
     * Returns the SQL to get the sine of a value.
992
     *
993
     * @param string $value
994
     *
995
     * @return string
996
     */
997
    public function getSinExpression($value)
998
    {
999
        return 'SIN(' . $value . ')';
1000
    }
1001
1002
    /**
1003
     * Returns the SQL to get the PI value.
1004
     *
1005
     * @return string
1006
     */
1007
    public function getPiExpression()
1008
    {
1009
        return 'PI()';
1010
    }
1011
1012
    /**
1013
     * Returns the SQL to get the cosine of a value.
1014
     *
1015
     * @param string $value
1016
     *
1017
     * @return string
1018
     */
1019
    public function getCosExpression($value)
1020
    {
1021
        return 'COS(' . $value . ')';
1022
    }
1023
1024
    /**
1025
     * Returns the SQL to calculate the difference in days between the two passed dates.
1026
     *
1027
     * Computes diff = date1 - date2.
1028
     *
1029
     * @param string $date1
1030
     * @param string $date2
1031
     *
1032
     * @return string
1033
     *
1034
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1035
     */
1036
    public function getDateDiffExpression($date1, $date2)
1037
    {
1038
        throw DBALException::notSupported(__METHOD__);
1039
    }
1040
1041
    /**
1042
     * Returns the SQL to add the number of given seconds to a date.
1043
     *
1044
     * @param string  $date
1045
     * @param integer $seconds
1046
     *
1047
     * @return string
1048
     *
1049
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1050
     */
1051 6
    public function getDateAddSecondsExpression($date, $seconds)
1052
    {
1053 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1054
    }
1055
1056
    /**
1057
     * Returns the SQL to subtract the number of given seconds from a date.
1058
     *
1059
     * @param string  $date
1060
     * @param integer $seconds
1061
     *
1062
     * @return string
1063
     *
1064
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1065
     */
1066 6
    public function getDateSubSecondsExpression($date, $seconds)
1067
    {
1068 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, self::DATE_INTERVAL_UNIT_SECOND);
1069
    }
1070
1071
    /**
1072
     * Returns the SQL to add the number of given minutes to a date.
1073
     *
1074
     * @param string  $date
1075
     * @param integer $minutes
1076
     *
1077
     * @return string
1078
     *
1079
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1080
     */
1081 6
    public function getDateAddMinutesExpression($date, $minutes)
1082
    {
1083 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1084
    }
1085
1086
    /**
1087
     * Returns the SQL to subtract the number of given minutes from a date.
1088
     *
1089
     * @param string  $date
1090
     * @param integer $minutes
1091
     *
1092
     * @return string
1093
     *
1094
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1095
     */
1096 6
    public function getDateSubMinutesExpression($date, $minutes)
1097
    {
1098 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, self::DATE_INTERVAL_UNIT_MINUTE);
1099
    }
1100
1101
    /**
1102
     * Returns the SQL to add the number of given hours to a date.
1103
     *
1104
     * @param string  $date
1105
     * @param integer $hours
1106
     *
1107
     * @return string
1108
     *
1109
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1110
     */
1111 6
    public function getDateAddHourExpression($date, $hours)
1112
    {
1113 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1114
    }
1115
1116
    /**
1117
     * Returns the SQL to subtract the number of given hours to a date.
1118
     *
1119
     * @param string  $date
1120
     * @param integer $hours
1121
     *
1122
     * @return string
1123
     *
1124
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1125
     */
1126 6
    public function getDateSubHourExpression($date, $hours)
1127
    {
1128 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, self::DATE_INTERVAL_UNIT_HOUR);
1129
    }
1130
1131
    /**
1132
     * Returns the SQL to add the number of given days to a date.
1133
     *
1134
     * @param string  $date
1135
     * @param integer $days
1136
     *
1137
     * @return string
1138
     *
1139
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1140
     */
1141 6
    public function getDateAddDaysExpression($date, $days)
1142
    {
1143 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, self::DATE_INTERVAL_UNIT_DAY);
1144
    }
1145
1146
    /**
1147
     * Returns the SQL to subtract the number of given days to a date.
1148
     *
1149
     * @param string  $date
1150
     * @param integer $days
1151
     *
1152
     * @return string
1153
     *
1154
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1155
     */
1156 6
    public function getDateSubDaysExpression($date, $days)
1157
    {
1158 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, self::DATE_INTERVAL_UNIT_DAY);
1159
    }
1160
1161
    /**
1162
     * Returns the SQL to add the number of given weeks to a date.
1163
     *
1164
     * @param string  $date
1165
     * @param integer $weeks
1166
     *
1167
     * @return string
1168
     *
1169
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1170
     */
1171 6
    public function getDateAddWeeksExpression($date, $weeks)
1172
    {
1173 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1174
    }
1175
1176
    /**
1177
     * Returns the SQL to subtract the number of given weeks from a date.
1178
     *
1179
     * @param string  $date
1180
     * @param integer $weeks
1181
     *
1182
     * @return string
1183
     *
1184
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1185
     */
1186 6
    public function getDateSubWeeksExpression($date, $weeks)
1187
    {
1188 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, self::DATE_INTERVAL_UNIT_WEEK);
1189
    }
1190
1191
    /**
1192
     * Returns the SQL to add the number of given months to a date.
1193
     *
1194
     * @param string  $date
1195
     * @param integer $months
1196
     *
1197
     * @return string
1198
     *
1199
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1200
     */
1201 6
    public function getDateAddMonthExpression($date, $months)
1202
    {
1203 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, self::DATE_INTERVAL_UNIT_MONTH);
1204
    }
1205
1206
    /**
1207
     * Returns the SQL to subtract the number of given months to a date.
1208
     *
1209
     * @param string  $date
1210
     * @param integer $months
1211
     *
1212
     * @return string
1213
     *
1214
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1215
     */
1216 6
    public function getDateSubMonthExpression($date, $months)
1217
    {
1218 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, self::DATE_INTERVAL_UNIT_MONTH);
1219
    }
1220
1221
    /**
1222
     * Returns the SQL to add the number of given quarters to a date.
1223
     *
1224
     * @param string  $date
1225
     * @param integer $quarters
1226
     *
1227
     * @return string
1228
     *
1229
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1230
     */
1231 6
    public function getDateAddQuartersExpression($date, $quarters)
1232
    {
1233 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1234
    }
1235
1236
    /**
1237
     * Returns the SQL to subtract the number of given quarters from a date.
1238
     *
1239
     * @param string  $date
1240
     * @param integer $quarters
1241
     *
1242
     * @return string
1243
     *
1244
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1245
     */
1246 6
    public function getDateSubQuartersExpression($date, $quarters)
1247
    {
1248 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, self::DATE_INTERVAL_UNIT_QUARTER);
1249
    }
1250
1251
    /**
1252
     * Returns the SQL to add the number of given years to a date.
1253
     *
1254
     * @param string  $date
1255
     * @param integer $years
1256
     *
1257
     * @return string
1258
     *
1259
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1260
     */
1261 6
    public function getDateAddYearsExpression($date, $years)
1262
    {
1263 6
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, self::DATE_INTERVAL_UNIT_YEAR);
1264
    }
1265
1266
    /**
1267
     * Returns the SQL to subtract the number of given years from a date.
1268
     *
1269
     * @param string  $date
1270
     * @param integer $years
1271
     *
1272
     * @return string
1273
     *
1274
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1275
     */
1276 6
    public function getDateSubYearsExpression($date, $years)
1277
    {
1278 6
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, self::DATE_INTERVAL_UNIT_YEAR);
1279
    }
1280
1281
    /**
1282
     * Returns the SQL for a date arithmetic expression.
1283
     *
1284
     * @param string  $date     The column or literal representing a date to perform the arithmetic operation on.
1285
     * @param string  $operator The arithmetic operator (+ or -).
1286
     * @param integer $interval The interval that shall be calculated into the date.
1287
     * @param string  $unit     The unit of the interval that shall be calculated into the date.
1288
     *                          One of the DATE_INTERVAL_UNIT_* constants.
1289
     *
1290
     * @return string
1291
     *
1292
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1293
     */
1294
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
1295
    {
1296
        throw DBALException::notSupported(__METHOD__);
1297
    }
1298
1299
    /**
1300
     * Returns the SQL bit AND comparison expression.
1301
     *
1302
     * @param string $value1
1303
     * @param string $value2
1304
     *
1305
     * @return string
1306
     */
1307 15
    public function getBitAndComparisonExpression($value1, $value2)
1308
    {
1309 15
        return '(' . $value1 . ' & ' . $value2 . ')';
1310
    }
1311
1312
    /**
1313
     * Returns the SQL bit OR comparison expression.
1314
     *
1315
     * @param string $value1
1316
     * @param string $value2
1317
     *
1318
     * @return string
1319
     */
1320 15
    public function getBitOrComparisonExpression($value1, $value2)
1321
    {
1322 15
        return '(' . $value1 . ' | ' . $value2 . ')';
1323
    }
1324
1325
    /**
1326
     * Returns the FOR UPDATE expression.
1327
     *
1328
     * @return string
1329
     */
1330
    public function getForUpdateSQL()
1331
    {
1332
        return 'FOR UPDATE';
1333
    }
1334
1335
    /**
1336
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1337
     *
1338
     * @param string       $fromClause The FROM clause to append the hint for the given lock mode to.
1339
     * @param integer|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1340
     *                                 be appended to the FROM clause.
1341
     *
1342
     * @return string
1343
     */
1344
    public function appendLockHint($fromClause, $lockMode)
1345
    {
1346
        return $fromClause;
1347
    }
1348
1349
    /**
1350
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1351
     *
1352
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1353
     * vendors allow to lighten this constraint up to be a real read lock.
1354
     *
1355
     * @return string
1356
     */
1357
    public function getReadLockSQL()
1358
    {
1359
        return $this->getForUpdateSQL();
1360
    }
1361
1362
    /**
1363
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1364
     *
1365
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1366
     *
1367
     * @return string
1368
     */
1369
    public function getWriteLockSQL()
1370
    {
1371
        return $this->getForUpdateSQL();
1372
    }
1373
1374
    /**
1375
     * Returns the SQL snippet to drop an existing database.
1376
     *
1377
     * @param string $database The name of the database that should be dropped.
1378
     *
1379
     * @return string
1380
     */
1381 4
    public function getDropDatabaseSQL($database)
1382
    {
1383 4
        return 'DROP DATABASE ' . $database;
1384
    }
1385
1386
    /**
1387
     * Returns the SQL snippet to drop an existing table.
1388
     *
1389
     * @param \Doctrine\DBAL\Schema\Table|string $table
1390
     *
1391
     * @return string
1392
     *
1393
     * @throws \InvalidArgumentException
1394
     */
1395 102
    public function getDropTableSQL($table)
1396
    {
1397 102
        $tableArg = $table;
1398
1399 102
        if ($table instanceof Table) {
1400 27
            $table = $table->getQuotedName($this);
1401 87
        } elseif (!is_string($table)) {
1402
            throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1403
        }
1404
1405 102
        if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1406 16
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1407 16
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1408
1409 16
            if ($eventArgs->isDefaultPrevented()) {
1410
                return $eventArgs->getSql();
1411
            }
1412
        }
1413
1414 102
        return 'DROP TABLE ' . $table;
1415
    }
1416
1417
    /**
1418
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1419
     *
1420
     * @param \Doctrine\DBAL\Schema\Table|string $table
1421
     *
1422
     * @return string
1423
     */
1424 2
    public function getDropTemporaryTableSQL($table)
1425
    {
1426 2
        return $this->getDropTableSQL($table);
1427
    }
1428
1429
    /**
1430
     * Returns the SQL to drop an index from a table.
1431
     *
1432
     * @param \Doctrine\DBAL\Schema\Index|string $index
1433
     * @param \Doctrine\DBAL\Schema\Table|string $table
1434
     *
1435
     * @return string
1436
     *
1437
     * @throws \InvalidArgumentException
1438
     */
1439 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...
1440
    {
1441 9
        if ($index instanceof Index) {
1442 8
            $index = $index->getQuotedName($this);
1443 1
        } elseif (!is_string($index)) {
1444
            throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1445
        }
1446
1447 9
        return 'DROP INDEX ' . $index;
1448
    }
1449
1450
    /**
1451
     * Returns the SQL to drop a constraint.
1452
     *
1453
     * @param \Doctrine\DBAL\Schema\Constraint|string $constraint
1454
     * @param \Doctrine\DBAL\Schema\Table|string      $table
1455
     *
1456
     * @return string
1457
     */
1458 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...
1459
    {
1460 31
        if (! $constraint instanceof Constraint) {
1461 23
            $constraint = new Identifier($constraint);
1462
        }
1463
1464 31
        if (! $table instanceof Table) {
1465 31
            $table = new Identifier($table);
1466
        }
1467
1468 31
        $constraint = $constraint->getQuotedName($this);
1469 31
        $table = $table->getQuotedName($this);
1470
1471 31
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1472
    }
1473
1474
    /**
1475
     * Returns the SQL to drop a foreign key.
1476
     *
1477
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint|string $foreignKey
1478
     * @param \Doctrine\DBAL\Schema\Table|string                $table
1479
     *
1480
     * @return string
1481
     */
1482 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...
1483
    {
1484 17
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1485 7
            $foreignKey = new Identifier($foreignKey);
1486
        }
1487
1488 17
        if (! $table instanceof Table) {
1489 17
            $table = new Identifier($table);
1490
        }
1491
1492 17
        $foreignKey = $foreignKey->getQuotedName($this);
1493 17
        $table = $table->getQuotedName($this);
1494
1495 17
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1496
    }
1497
1498
    /**
1499
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1500
     * on this platform.
1501
     *
1502
     * @param \Doctrine\DBAL\Schema\Table   $table
1503
     * @param integer                       $createFlags
1504
     *
1505
     * @return array The sequence of SQL statements.
1506
     *
1507
     * @throws \Doctrine\DBAL\DBALException
1508
     * @throws \InvalidArgumentException
1509
     */
1510 350
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1511
    {
1512 350
        if ( ! is_int($createFlags)) {
1513
            throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
1514
        }
1515
1516 350
        if (count($table->getColumns()) === 0) {
1517 16
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1518
        }
1519
1520 334
        $tableName = $table->getQuotedName($this);
1521 334
        $options = $table->getOptions();
1522 334
        $options['uniqueConstraints'] = [];
1523 334
        $options['indexes'] = [];
1524 334
        $options['primary'] = [];
1525
1526 334
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1527 313
            foreach ($table->getIndexes() as $index) {
1528
                /* @var $index Index */
1529 232
                if ($index->isPrimary()) {
1530 175
                    $options['primary']       = $index->getQuotedColumns($this);
1531 175
                    $options['primary_index'] = $index;
1532
                } else {
1533 232
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1534
                }
1535
            }
1536
        }
1537
1538 334
        $columnSql = [];
1539 334
        $columns = [];
1540
1541 334
        foreach ($table->getColumns() as $column) {
1542
            /* @var \Doctrine\DBAL\Schema\Column $column */
1543
1544 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...
1545 16
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1546 16
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1547
1548 16
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1549
1550 16
                if ($eventArgs->isDefaultPrevented()) {
1551
                    continue;
1552
                }
1553
            }
1554
1555 334
            $columnData = $column->toArray();
1556 334
            $columnData['name'] = $column->getQuotedName($this);
1557 334
            $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false;
1558 334
            $columnData['comment'] = $this->getColumnComment($column);
1559
1560 334
            if (strtolower($columnData['type']) == "string" && $columnData['length'] === null) {
1561 134
                $columnData['length'] = 255;
1562
            }
1563
1564 334
            if (in_array($column->getName(), $options['primary'])) {
1565 157
                $columnData['primary'] = true;
1566
            }
1567
1568 334
            $columns[$columnData['name']] = $columnData;
1569
        }
1570
1571 334
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1572 168
            $options['foreignKeys'] = [];
1573 168
            foreach ($table->getForeignKeys() as $fkConstraint) {
1574 28
                $options['foreignKeys'][] = $fkConstraint;
1575
            }
1576
        }
1577
1578 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...
1579 16
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1580 16
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1581
1582 16
            if ($eventArgs->isDefaultPrevented()) {
1583
                return array_merge($eventArgs->getSql(), $columnSql);
1584
            }
1585
        }
1586
1587 334
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1588 334
        if ($this->supportsCommentOnStatement()) {
1589 111
            foreach ($table->getColumns() as $column) {
1590 111
                $comment = $this->getColumnComment($column);
1591
1592 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...
1593 111
                    $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1594
                }
1595
            }
1596
        }
1597
1598 334
        return array_merge($sql, $columnSql);
1599
    }
1600
1601
    /**
1602
     * @param string $tableName
1603
     * @param string $columnName
1604
     * @param string $comment
1605
     *
1606
     * @return string
1607
     */
1608 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...
1609
    {
1610 31
        $tableName = new Identifier($tableName);
1611 31
        $columnName = new Identifier($columnName);
1612 31
        $comment = $this->quoteStringLiteral($comment);
1613
1614 31
        return "COMMENT ON COLUMN " . $tableName->getQuotedName($this) . "." . $columnName->getQuotedName($this) .
1615 31
            " IS " . $comment;
1616
    }
1617
1618
    /**
1619
     * Returns the SQL to create inline comment on a column.
1620
     *
1621
     * @param string $comment
1622
     *
1623
     * @return string
1624
     *
1625
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1626
     */
1627 31
    public function getInlineColumnCommentSQL($comment)
1628
    {
1629 31
        if (! $this->supportsInlineColumnComments()) {
1630 13
            throw DBALException::notSupported(__METHOD__);
1631
        }
1632
1633 18
        return "COMMENT " . $this->quoteStringLiteral($comment);
1634
    }
1635
1636
    /**
1637
     * Returns the SQL used to create a table.
1638
     *
1639
     * @param string $tableName
1640
     * @param array  $columns
1641
     * @param array  $options
1642
     *
1643
     * @return array
1644
     */
1645 23
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1646
    {
1647 23
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1648
1649 23
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1650
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1651
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1652
            }
1653
        }
1654
1655 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...
1656 10
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1657
        }
1658
1659 23
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1660
            foreach ($options['indexes'] as $index => $definition) {
1661
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1662
            }
1663
        }
1664
1665 23
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1666
1667 23
        $check = $this->getCheckDeclarationSQL($columns);
1668 23
        if ( ! empty($check)) {
1669 1
            $query .= ', ' . $check;
1670
        }
1671 23
        $query .= ')';
1672
1673 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...
1674
1675 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...
1676 3
            foreach ((array) $options['foreignKeys'] as $definition) {
1677 3
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1678
            }
1679
        }
1680
1681 23
        return $sql;
1682
    }
1683
1684
    /**
1685
     * @return string
1686
     */
1687 2
    public function getCreateTemporaryTableSnippetSQL()
1688
    {
1689 2
        return "CREATE TEMPORARY TABLE";
1690
    }
1691
1692
    /**
1693
     * Returns the SQL to create a sequence on this platform.
1694
     *
1695
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1696
     *
1697
     * @return string
1698
     *
1699
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1700
     */
1701
    public function getCreateSequenceSQL(Sequence $sequence)
1702
    {
1703
        throw DBALException::notSupported(__METHOD__);
1704
    }
1705
1706
    /**
1707
     * Returns the SQL to change a sequence on this platform.
1708
     *
1709
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
1710
     *
1711
     * @return string
1712
     *
1713
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1714
     */
1715
    public function getAlterSequenceSQL(Sequence $sequence)
1716
    {
1717
        throw DBALException::notSupported(__METHOD__);
1718
    }
1719
1720
    /**
1721
     * Returns the SQL to create a constraint on a table on this platform.
1722
     *
1723
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
1724
     * @param \Doctrine\DBAL\Schema\Table|string $table
1725
     *
1726
     * @return string
1727
     *
1728
     * @throws \InvalidArgumentException
1729
     */
1730 14
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1731
    {
1732 14
        if ($table instanceof Table) {
1733
            $table = $table->getQuotedName($this);
1734
        }
1735
1736 14
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1737
1738 14
        $columnList = '('. implode(', ', $constraint->getQuotedColumns($this)) . ')';
1739
1740 14
        $referencesClause = '';
1741 14
        if ($constraint instanceof Index) {
1742 14
            if ($constraint->isPrimary()) {
1743 14
                $query .= ' PRIMARY KEY';
1744 11
            } elseif ($constraint->isUnique()) {
1745 11
                $query .= ' UNIQUE';
1746
            } else {
1747
                throw new \InvalidArgumentException(
1748 14
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1749
                );
1750
            }
1751 11
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1752 11
            $query .= ' FOREIGN KEY';
1753
1754 11
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1755 11
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1756
        }
1757 14
        $query .= ' '.$columnList.$referencesClause;
1758
1759 14
        return $query;
1760
    }
1761
1762
    /**
1763
     * Returns the SQL to create an index on a table on this platform.
1764
     *
1765
     * @param \Doctrine\DBAL\Schema\Index        $index
1766
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
1767
     *
1768
     * @return string
1769
     *
1770
     * @throws \InvalidArgumentException
1771
     */
1772 135
    public function getCreateIndexSQL(Index $index, $table)
1773
    {
1774 135
        if ($table instanceof Table) {
1775 1
            $table = $table->getQuotedName($this);
1776
        }
1777 135
        $name = $index->getQuotedName($this);
1778 135
        $columns = $index->getQuotedColumns($this);
1779
1780 135
        if (count($columns) == 0) {
1781
            throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
1782
        }
1783
1784 135
        if ($index->isPrimary()) {
1785 16
            return $this->getCreatePrimaryKeySQL($index, $table);
1786
        }
1787
1788 121
        $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1789 121
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')' . $this->getPartialIndexSQL($index);
1790
1791 121
        return $query;
1792
    }
1793
1794
    /**
1795
     * Adds condition for partial index.
1796
     *
1797
     * @param \Doctrine\DBAL\Schema\Index $index
1798
     *
1799
     * @return string
1800
     */
1801 158
    protected function getPartialIndexSQL(Index $index)
1802
    {
1803 158
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1804 4
            return  ' WHERE ' . $index->getOption('where');
1805
        }
1806
1807 154
        return '';
1808
    }
1809
1810
    /**
1811
     * Adds additional flags for index generation.
1812
     *
1813
     * @param \Doctrine\DBAL\Schema\Index $index
1814
     *
1815
     * @return string
1816
     */
1817 60
    protected function getCreateIndexSQLFlags(Index $index)
1818
    {
1819 60
        return $index->isUnique() ? 'UNIQUE ' : '';
1820
    }
1821
1822
    /**
1823
     * Returns the SQL to create an unnamed primary key constraint.
1824
     *
1825
     * @param \Doctrine\DBAL\Schema\Index        $index
1826
     * @param \Doctrine\DBAL\Schema\Table|string $table
1827
     *
1828
     * @return string
1829
     */
1830 12
    public function getCreatePrimaryKeySQL(Index $index, $table)
1831
    {
1832 12
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
1833
    }
1834
1835
    /**
1836
     * Returns the SQL to create a named schema.
1837
     *
1838
     * @param string $schemaName
1839
     *
1840
     * @return string
1841
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1842
     */
1843 9
    public function getCreateSchemaSQL($schemaName)
1844
    {
1845 9
        throw DBALException::notSupported(__METHOD__);
1846
    }
1847
1848
    /**
1849
     * Quotes a string so that it can be safely used as a table or column name,
1850
     * even if it is a reserved word of the platform. This also detects identifier
1851
     * chains separated by dot and quotes them independently.
1852
     *
1853
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1854
     * you SHOULD use them. In general, they end up causing way more
1855
     * problems than they solve.
1856
     *
1857
     * @param string $str The identifier name to be quoted.
1858
     *
1859
     * @return string The quoted identifier string.
1860
     */
1861 348
    public function quoteIdentifier($str)
1862
    {
1863 348
        if (strpos($str, ".") !== false) {
1864 16
            $parts = array_map([$this, "quoteSingleIdentifier"], explode(".", $str));
1865
1866 16
            return implode(".", $parts);
1867
        }
1868
1869 348
        return $this->quoteSingleIdentifier($str);
1870
    }
1871
1872
    /**
1873
     * Quotes a single identifier (no dot chain separation).
1874
     *
1875
     * @param string $str The identifier name to be quoted.
1876
     *
1877
     * @return string The quoted identifier string.
1878
     */
1879 318
    public function quoteSingleIdentifier($str)
1880
    {
1881 318
        $c = $this->getIdentifierQuoteCharacter();
1882
1883 318
        return $c . str_replace($c, $c.$c, $str) . $c;
1884
    }
1885
1886
    /**
1887
     * Returns the SQL to create a new foreign key.
1888
     *
1889
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The foreign key constraint.
1890
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
1891
     *
1892
     * @return string
1893
     */
1894 67
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1895
    {
1896 67
        if ($table instanceof Table) {
1897 1
            $table = $table->getQuotedName($this);
1898
        }
1899
1900 67
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1901
1902 67
        return $query;
1903
    }
1904
1905
    /**
1906
     * Gets the SQL statements for altering an existing table.
1907
     *
1908
     * This method returns an array of SQL statements, since some platforms need several statements.
1909
     *
1910
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1911
     *
1912
     * @return array
1913
     *
1914
     * @throws \Doctrine\DBAL\DBALException If not supported on this platform.
1915
     */
1916
    public function getAlterTableSQL(TableDiff $diff)
1917
    {
1918
        throw DBALException::notSupported(__METHOD__);
1919
    }
1920
1921
    /**
1922
     * @param \Doctrine\DBAL\Schema\Column    $column
1923
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1924
     * @param array                           $columnSql
1925
     *
1926
     * @return boolean
1927
     */
1928 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...
1929
    {
1930 85
        if (null === $this->_eventManager) {
1931 68
            return false;
1932
        }
1933
1934 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1935 1
            return false;
1936
        }
1937
1938 16
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1939 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1940
1941 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1942
1943 16
        return $eventArgs->isDefaultPrevented();
1944
    }
1945
1946
    /**
1947
     * @param \Doctrine\DBAL\Schema\Column    $column
1948
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
1949
     * @param array                           $columnSql
1950
     *
1951
     * @return boolean
1952
     */
1953 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...
1954
    {
1955 69
        if (null === $this->_eventManager) {
1956 52
            return false;
1957
        }
1958
1959 17
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
1960 1
            return false;
1961
        }
1962
1963 16
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
1964 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
1965
1966 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1967
1968 16
        return $eventArgs->isDefaultPrevented();
1969
    }
1970
1971
    /**
1972
     * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff
1973
     * @param \Doctrine\DBAL\Schema\TableDiff  $diff
1974
     * @param array                            $columnSql
1975
     *
1976
     * @return boolean
1977
     */
1978 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...
1979
    {
1980 168
        if (null === $this->_eventManager) {
1981 140
            return false;
1982
        }
1983
1984 28
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
1985 12
            return false;
1986
        }
1987
1988 16
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
1989 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
1990
1991 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1992
1993 16
        return $eventArgs->isDefaultPrevented();
1994
    }
1995
1996
    /**
1997
     * @param string                          $oldColumnName
1998
     * @param \Doctrine\DBAL\Schema\Column    $column
1999
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2000
     * @param array                           $columnSql
2001
     *
2002
     * @return boolean
2003
     */
2004 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...
2005
    {
2006 68
        if (null === $this->_eventManager) {
2007 52
            return false;
2008
        }
2009
2010 16
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2011
            return false;
2012
        }
2013
2014 16
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2015 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2016
2017 16
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2018
2019 16
        return $eventArgs->isDefaultPrevented();
2020
    }
2021
2022
    /**
2023
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2024
     * @param array                           $sql
2025
     *
2026
     * @return boolean
2027
     */
2028 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...
2029
    {
2030 315
        if (null === $this->_eventManager) {
2031 280
            return false;
2032
        }
2033
2034 35
        if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2035 19
            return false;
2036
        }
2037
2038 16
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2039 16
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2040
2041 16
        $sql = array_merge($sql, $eventArgs->getSql());
2042
2043 16
        return $eventArgs->isDefaultPrevented();
2044
    }
2045
2046
    /**
2047
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2048
     *
2049
     * @return array
2050
     */
2051 283
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2052
    {
2053 283
        $tableName = $diff->getName($this)->getQuotedName($this);
2054
2055 283
        $sql = [];
2056 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...
2057 283
            foreach ($diff->removedForeignKeys as $foreignKey) {
2058 21
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2059
            }
2060 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2061 17
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2062
            }
2063
        }
2064
2065 283
        foreach ($diff->removedIndexes as $index) {
2066 8
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2067
        }
2068 283
        foreach ($diff->changedIndexes as $index) {
2069 11
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2070
        }
2071
2072 283
        return $sql;
2073
    }
2074
2075
    /**
2076
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2077
     *
2078
     * @return array
2079
     */
2080 283
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2081
    {
2082 283
        $tableName = (false !== $diff->newName)
2083 30
            ? $diff->getNewName()->getQuotedName($this)
2084 283
            : $diff->getName($this)->getQuotedName($this);
2085
2086 283
        $sql = [];
2087
2088 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...
2089 283
            foreach ($diff->addedForeignKeys as $foreignKey) {
2090 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2091
            }
2092
2093 283
            foreach ($diff->changedForeignKeys as $foreignKey) {
2094 17
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2095
            }
2096
        }
2097
2098 283
        foreach ($diff->addedIndexes as $index) {
2099 2
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2100
        }
2101
2102 283
        foreach ($diff->changedIndexes as $index) {
2103 11
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2104
        }
2105
2106 283
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2107 75
            $oldIndexName = new Identifier($oldIndexName);
2108 75
            $sql          = array_merge(
2109 75
                $sql,
2110 75
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2111
            );
2112
        }
2113
2114 283
        return $sql;
2115
    }
2116
2117
    /**
2118
     * Returns the SQL for renaming an index on a table.
2119
     *
2120
     * @param string                      $oldIndexName The name of the index to rename from.
2121
     * @param \Doctrine\DBAL\Schema\Index $index        The definition of the index to rename to.
2122
     * @param string                      $tableName    The table to rename the given index on.
2123
     *
2124
     * @return array The sequence of SQL statements for renaming the given index.
2125
     */
2126 5
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2127
    {
2128
        return [
2129 5
            $this->getDropIndexSQL($oldIndexName, $tableName),
2130 5
            $this->getCreateIndexSQL($index, $tableName)
2131
        ];
2132
    }
2133
2134
    /**
2135
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2136
     *
2137
     * @param \Doctrine\DBAL\Schema\TableDiff $diff
2138
     *
2139
     * @return array
2140
     */
2141
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2142
    {
2143
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2144
    }
2145
2146
    /**
2147
     * Gets declaration of a number of fields in bulk.
2148
     *
2149
     * @param array $fields A multidimensional associative array.
2150
     *                      The first dimension determines the field name, while the second
2151
     *                      dimension is keyed with the name of the properties
2152
     *                      of the field being declared as array indexes. Currently, the types
2153
     *                      of supported field properties are as follows:
2154
     *
2155
     *      length
2156
     *          Integer value that determines the maximum length of the text
2157
     *          field. If this argument is missing the field should be
2158
     *          declared to have the longest length allowed by the DBMS.
2159
     *
2160
     *      default
2161
     *          Text value to be used as default for this field.
2162
     *
2163
     *      notnull
2164
     *          Boolean flag that indicates whether this field is constrained
2165
     *          to not be set to null.
2166
     *      charset
2167
     *          Text value with the default CHARACTER SET for this field.
2168
     *      collation
2169
     *          Text value with the default COLLATION for this field.
2170
     *      unique
2171
     *          unique constraint
2172
     *
2173
     * @return string
2174
     */
2175 334
    public function getColumnDeclarationListSQL(array $fields)
2176
    {
2177 334
        $queryFields = [];
2178
2179 334
        foreach ($fields as $fieldName => $field) {
2180 334
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2181
        }
2182
2183 334
        return implode(', ', $queryFields);
2184
    }
2185
2186
    /**
2187
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2188
     * field to be used in statements like CREATE TABLE.
2189
     *
2190
     * @param string $name  The name the field to be declared.
2191
     * @param array  $field An associative array with the name of the properties
2192
     *                      of the field being declared as array indexes. Currently, the types
2193
     *                      of supported field properties are as follows:
2194
     *
2195
     *      length
2196
     *          Integer value that determines the maximum length of the text
2197
     *          field. If this argument is missing the field should be
2198
     *          declared to have the longest length allowed by the DBMS.
2199
     *
2200
     *      default
2201
     *          Text value to be used as default for this field.
2202
     *
2203
     *      notnull
2204
     *          Boolean flag that indicates whether this field is constrained
2205
     *          to not be set to null.
2206
     *      charset
2207
     *          Text value with the default CHARACTER SET for this field.
2208
     *      collation
2209
     *          Text value with the default COLLATION for this field.
2210
     *      unique
2211
     *          unique constraint
2212
     *      check
2213
     *          column check constraint
2214
     *      columnDefinition
2215
     *          a string that defines the complete column
2216
     *
2217
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2218
     */
2219 364
    public function getColumnDeclarationSQL($name, array $field)
2220
    {
2221 364
        if (isset($field['columnDefinition'])) {
2222 13
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2223
        } else {
2224 352
            $default = $this->getDefaultValueDeclarationSQL($field);
2225
2226 352
            $charset = (isset($field['charset']) && $field['charset']) ?
2227 352
                    ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2228
2229 352
            $collation = (isset($field['collation']) && $field['collation']) ?
2230 352
                    ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2231
2232 352
            $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
2233
2234 352
            $unique = (isset($field['unique']) && $field['unique']) ?
2235 352
                    ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2236
2237 352
            $check = (isset($field['check']) && $field['check']) ?
2238 352
                    ' ' . $field['check'] : '';
2239
2240 352
            $typeDecl = $field['type']->getSQLDeclaration($field, $this);
2241 352
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2242
2243 352
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2244 45
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2245
            }
2246
        }
2247
2248 364
        return $name . ' ' . $columnDef;
2249
    }
2250
2251
    /**
2252
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2253
     *
2254
     * @param array $columnDef
2255
     *
2256
     * @return string
2257
     */
2258 120
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2259
    {
2260 120
        $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
2261 120
            ? 10 : $columnDef['precision'];
2262 120
        $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
2263 120
            ? 0 : $columnDef['scale'];
2264
2265 120
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2266
    }
2267
2268
    /**
2269
     * Obtains DBMS specific SQL code portion needed to set a default value
2270
     * declaration to be used in statements like CREATE TABLE.
2271
     *
2272
     * @param array $field The field definition array.
2273
     *
2274
     * @return string DBMS specific SQL code portion needed to set a default value.
2275
     */
2276 410
    public function getDefaultValueDeclarationSQL($field)
2277
    {
2278 410
        $default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
2279
2280 410
        if (isset($field['default'])) {
2281 64
            $default = " DEFAULT '".$field['default']."'";
2282 64
            if (isset($field['type'])) {
2283 64
                if (in_array((string) $field['type'], ["Integer", "BigInt", "SmallInt"])) {
2284 20
                    $default = " DEFAULT ".$field['default'];
2285 46 View Code Duplication
                } elseif (in_array((string) $field['type'], ['DateTime', 'DateTimeTz']) && $field['default'] == $this->getCurrentTimestampSQL()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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