Completed
Pull Request — master (#3626)
by Dallas
14:09
created

AbstractPlatform   F

Complexity

Total Complexity 390

Size/Duplication

Total Lines 3556
Duplicated Lines 0 %

Test Coverage

Coverage 80.28%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 390
eloc 657
c 3
b 0
f 1
dl 0
loc 3556
ccs 676
cts 842
cp 0.8028
rs 1.943

209 Methods

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

How to fix   Complexity   

Complex Class

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.

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
namespace Doctrine\DBAL\Platforms;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\DBAL\DBALException;
7
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
8
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
9
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
10
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
11
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
12
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
13
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
14
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
15
use Doctrine\DBAL\Events;
16
use Doctrine\DBAL\Platforms\Keywords\KeywordList;
17
use Doctrine\DBAL\Schema\Column;
18
use Doctrine\DBAL\Schema\ColumnDiff;
19
use Doctrine\DBAL\Schema\Constraint;
20
use Doctrine\DBAL\Schema\Expression;
21
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
22
use Doctrine\DBAL\Schema\Identifier;
23
use Doctrine\DBAL\Schema\Index;
24
use Doctrine\DBAL\Schema\Sequence;
25
use Doctrine\DBAL\Schema\Table;
26
use Doctrine\DBAL\Schema\TableDiff;
27
use Doctrine\DBAL\TransactionIsolationLevel;
28
use Doctrine\DBAL\Types;
29
use Doctrine\DBAL\Types\Type;
30
use InvalidArgumentException;
31
use UnexpectedValueException;
32
use const E_USER_DEPRECATED;
33
use function addcslashes;
34
use function array_map;
35
use function array_merge;
36
use function array_unique;
37
use function array_values;
38
use function assert;
39
use function count;
40
use function explode;
41
use function func_get_arg;
42
use function func_get_args;
43
use function func_num_args;
44
use function implode;
45
use function in_array;
46
use function is_array;
47
use function is_bool;
48
use function is_int;
49
use function is_string;
50
use function preg_quote;
51
use function preg_replace;
52
use function sprintf;
53
use function str_replace;
54
use function strlen;
55
use function strpos;
56
use function strtolower;
57
use function strtoupper;
58
use function trigger_error;
59
60
/**
61
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
62
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
63
 * They are a passive source of information.
64
 *
65
 * @todo Remove any unnecessary methods.
66
 */
67
abstract class AbstractPlatform
68
{
69
    public const CREATE_INDEXES = 1;
70
71
    public const CREATE_FOREIGNKEYS = 2;
72
73
    /**
74
     * @deprecated Use DateIntervalUnit::INTERVAL_UNIT_SECOND.
75
     */
76
    public const DATE_INTERVAL_UNIT_SECOND = DateIntervalUnit::SECOND;
77
78
    /**
79
     * @deprecated Use DateIntervalUnit::MINUTE.
80
     */
81
    public const DATE_INTERVAL_UNIT_MINUTE = DateIntervalUnit::MINUTE;
82
83
    /**
84
     * @deprecated Use DateIntervalUnit::HOUR.
85
     */
86
    public const DATE_INTERVAL_UNIT_HOUR = DateIntervalUnit::HOUR;
87
88
    /**
89
     * @deprecated Use DateIntervalUnit::DAY.
90
     */
91
    public const DATE_INTERVAL_UNIT_DAY = DateIntervalUnit::DAY;
92
93
    /**
94
     * @deprecated Use DateIntervalUnit::WEEK.
95
     */
96
    public const DATE_INTERVAL_UNIT_WEEK = DateIntervalUnit::WEEK;
97
98
    /**
99
     * @deprecated Use DateIntervalUnit::MONTH.
100
     */
101
    public const DATE_INTERVAL_UNIT_MONTH = DateIntervalUnit::MONTH;
102
103
    /**
104
     * @deprecated Use DateIntervalUnit::QUARTER.
105
     */
106
    public const DATE_INTERVAL_UNIT_QUARTER = DateIntervalUnit::QUARTER;
107
108
    /**
109
     * @deprecated Use DateIntervalUnit::QUARTER.
110
     */
111
    public const DATE_INTERVAL_UNIT_YEAR = DateIntervalUnit::YEAR;
112
113
    /**
114
     * @deprecated Use TrimMode::UNSPECIFIED.
115
     */
116
    public const TRIM_UNSPECIFIED = TrimMode::UNSPECIFIED;
117
118
    /**
119
     * @deprecated Use TrimMode::LEADING.
120
     */
121
    public const TRIM_LEADING = TrimMode::LEADING;
122
123
    /**
124
     * @deprecated Use TrimMode::TRAILING.
125
     */
126
    public const TRIM_TRAILING = TrimMode::TRAILING;
127
128
    /**
129
     * @deprecated Use TrimMode::BOTH.
130
     */
131
    public const TRIM_BOTH = TrimMode::BOTH;
132
133
    /** @var string[]|null */
134
    protected $doctrineTypeMapping = null;
135
136
    /**
137
     * Contains a list of all columns that should generate parseable column comments for type-detection
138
     * in reverse engineering scenarios.
139
     *
140
     * @var string[]|null
141
     */
142
    protected $doctrineTypeComments = null;
143
144
    /** @var EventManager */
145
    protected $_eventManager;
146
147
    /**
148
     * Holds the KeywordList instance for the current platform.
149
     *
150
     * @var KeywordList|null
151
     */
152
    protected $_keywords;
153
154 71502
    public function __construct()
155
    {
156 71502
    }
157
158
    /**
159
     * Sets the EventManager used by the Platform.
160
     */
161 64644
    public function setEventManager(EventManager $eventManager)
162
    {
163 64644
        $this->_eventManager = $eventManager;
164 64644
    }
165
166
    /**
167
     * Gets the EventManager used by the Platform.
168
     *
169
     * @return EventManager
170
     */
171 61849
    public function getEventManager()
172
    {
173 61849
        return $this->_eventManager;
174
    }
175
176
    /**
177
     * Returns the SQL snippet that declares a boolean column.
178
     *
179
     * @param mixed[] $columnDef
180
     *
181
     * @return string
182
     */
183
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
184
185
    /**
186
     * Returns the SQL snippet that declares a 4 byte integer column.
187
     *
188
     * @param mixed[] $columnDef
189
     *
190
     * @return string
191
     */
192
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
193
194
    /**
195
     * Returns the SQL snippet that declares an 8 byte integer column.
196
     *
197
     * @param mixed[] $columnDef
198
     *
199
     * @return string
200
     */
201
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
202
203
    /**
204
     * Returns the SQL snippet that declares a 2 byte integer column.
205
     *
206
     * @param mixed[] $columnDef
207
     *
208
     * @return string
209
     */
210
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
211
212
    /**
213
     * Returns the SQL snippet that declares common properties of an integer column.
214
     *
215
     * @param mixed[] $columnDef
216
     *
217
     * @return string
218
     */
219
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
220
221
    /**
222
     * Lazy load Doctrine Type Mappings.
223
     *
224
     * @return void
225
     */
226
    abstract protected function initializeDoctrineTypeMappings();
227
228
    /**
229
     * Initializes Doctrine Type Mappings with the platform defaults
230
     * and with all additional type mappings.
231
     *
232
     * @return void
233
     */
234 61929
    private function initializeAllDoctrineTypeMappings()
235
    {
236 61929
        $this->initializeDoctrineTypeMappings();
237
238 61929
        foreach (Type::getTypesMap() as $typeName => $className) {
239 61929
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
240 34497
                $this->doctrineTypeMapping[$dbType] = $typeName;
241
            }
242
        }
243 61929
    }
244
245
    /**
246
     * Returns the SQL snippet used to declare a VARCHAR column type.
247
     *
248
     * @param mixed[] $field
249
     *
250
     * @return string
251
     */
252 63990
    public function getVarcharTypeDeclarationSQL(array $field)
253
    {
254 63990
        if (! isset($field['length'])) {
255 60248
            $field['length'] = $this->getVarcharDefaultLength();
256
        }
257
258 63990
        $fixed = $field['fixed'] ?? false;
259
260 63990
        $maxLength = $fixed
261 61977
            ? $this->getCharMaxLength()
262 63990
            : $this->getVarcharMaxLength();
263
264 63990
        if ($field['length'] > $maxLength) {
265
            return $this->getClobTypeDeclarationSQL($field);
266
        }
267
268 63990
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
269
    }
270
271
    /**
272
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
273
     *
274
     * @param mixed[] $field The column definition.
275
     *
276
     * @return string
277
     */
278 60411
    public function getBinaryTypeDeclarationSQL(array $field)
279
    {
280 60411
        if (! isset($field['length'])) {
281 60356
            $field['length'] = $this->getBinaryDefaultLength();
282
        }
283
284 60411
        $fixed = $field['fixed'] ?? false;
285
286 60411
        $maxLength = $this->getBinaryMaxLength();
287
288 60411
        if ($field['length'] > $maxLength) {
289 58109
            if ($maxLength > 0) {
290 57849
                @trigger_error(sprintf(
291 24
                    'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.',
292 57849
                    $field['length'],
293 57849
                    $maxLength
294 57849
                ), E_USER_DEPRECATED);
295
            }
296
297 58109
            return $this->getBlobTypeDeclarationSQL($field);
298
        }
299
300 60387
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
301
    }
302
303
    /**
304
     * Returns the SQL snippet to declare a GUID/UUID field.
305
     *
306
     * By default this maps directly to a CHAR(36) and only maps to more
307
     * special datatypes when the underlying databases support this datatype.
308
     *
309
     * @param mixed[] $field
310
     *
311
     * @return string
312
     */
313 59579
    public function getGuidTypeDeclarationSQL(array $field)
314
    {
315 59579
        $field['length'] = 36;
316 59579
        $field['fixed']  = true;
317
318 59579
        return $this->getVarcharTypeDeclarationSQL($field);
319
    }
320
321
    /**
322
     * Returns the SQL snippet to declare a JSON field.
323
     *
324
     * By default this maps directly to a CLOB and only maps to more
325
     * special datatypes when the underlying databases support this datatype.
326
     *
327
     * @param mixed[] $field
328
     *
329
     * @return string
330
     */
331 57995
    public function getJsonTypeDeclarationSQL(array $field)
332
    {
333 57995
        return $this->getClobTypeDeclarationSQL($field);
334
    }
335
336
    /**
337
     * @param int  $length
338
     * @param bool $fixed
339
     *
340
     * @return string
341
     *
342
     * @throws DBALException If not supported on this platform.
343
     */
344
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
0 ignored issues
show
Unused Code introduced by
The parameter $fixed is not used and could be removed. ( Ignorable by Annotation )

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

344
    protected function getVarcharTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

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

Loading history...
345
    {
346
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
347
    }
348
349
    /**
350
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
351
     *
352
     * @param int  $length The length of the column.
353
     * @param bool $fixed  Whether the column length is fixed.
354
     *
355
     * @return string
356
     *
357
     * @throws DBALException If not supported on this platform.
358
     */
359
    protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
0 ignored issues
show
Unused Code introduced by
The parameter $fixed is not used and could be removed. ( Ignorable by Annotation )

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

359
    protected function getBinaryTypeDeclarationSQLSnippet($length, /** @scrutinizer ignore-unused */ $fixed)

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

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

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

811
            $expression .= /** @scrutinizer ignore-type */ $char . ' ';
Loading history...
812
        }
813
814 55715
        if ($mode || $char !== false) {
815 55689
            $expression .= 'FROM ';
816
        }
817
818 55715
        return 'TRIM(' . $expression . $str . ')';
819
    }
820
821
    /**
822
     * Returns the SQL snippet to trim trailing space characters from the expression.
823
     *
824
     * @param string $str Literal string or column name.
825
     *
826
     * @return string
827
     */
828 27808
    public function getRtrimExpression($str)
829
    {
830 27808
        return 'RTRIM(' . $str . ')';
831
    }
832
833
    /**
834
     * Returns the SQL snippet to trim leading space characters from the expression.
835
     *
836
     * @param string $str Literal string or column name.
837
     *
838
     * @return string
839
     */
840 27808
    public function getLtrimExpression($str)
841
    {
842 27808
        return 'LTRIM(' . $str . ')';
843
    }
844
845
    /**
846
     * Returns the SQL snippet to change all characters from the expression to uppercase,
847
     * according to the current character set mapping.
848
     *
849
     * @param string $str Literal string or column name.
850
     *
851
     * @return string
852
     */
853
    public function getUpperExpression($str)
854
    {
855
        return 'UPPER(' . $str . ')';
856
    }
857
858
    /**
859
     * Returns the SQL snippet to change all characters from the expression to lowercase,
860
     * according to the current character set mapping.
861
     *
862
     * @param string $str Literal string or column name.
863
     *
864
     * @return string
865
     */
866
    public function getLowerExpression($str)
867
    {
868
        return 'LOWER(' . $str . ')';
869
    }
870
871
    /**
872
     * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
873
     *
874
     * @param string    $str      Literal string.
875
     * @param string    $substr   Literal string to find.
876
     * @param int|false $startPos Position to start at, beginning of string by default.
877
     *
878
     * @return string
879
     *
880
     * @throws DBALException If not supported on this platform.
881
     */
882
    public function getLocateExpression($str, $substr, $startPos = false)
0 ignored issues
show
Unused Code introduced by
The parameter $substr is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

Loading history...
883
    {
884
        throw DBALException::notSupported(__METHOD__);
885
    }
886
887
    /**
888
     * Returns the SQL snippet to get the current system date.
889
     *
890
     * @return string
891
     */
892
    public function getNowExpression()
893
    {
894
        return 'NOW()';
895
    }
896
897
    /**
898
     * Returns a SQL snippet to get a substring inside an SQL statement.
899
     *
900
     * Note: Not SQL92, but common functionality.
901
     *
902
     * SQLite only supports the 2 parameter variant of this function.
903
     *
904
     * @param string   $value  An sql string literal or column name/alias.
905
     * @param int      $from   Where to start the substring portion.
906
     * @param int|null $length The substring portion length.
907
     *
908
     * @return string
909
     */
910
    public function getSubstringExpression($value, $from, $length = null)
911
    {
912
        if ($length === null) {
913
            return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
914
        }
915
916
        return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')';
917
    }
918
919
    /**
920
     * Returns a SQL snippet to concatenate the given expressions.
921
     *
922
     * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
923
     *
924
     * @return string
925
     */
926 46837
    public function getConcatExpression()
927
    {
928 46837
        return implode(' || ', func_get_args());
929
    }
930
931
    /**
932
     * Returns the SQL for a logical not.
933
     *
934
     * Example:
935
     * <code>
936
     * $q = new Doctrine_Query();
937
     * $e = $q->expr;
938
     * $q->select('*')->from('table')
939
     *   ->where($e->eq('id', $e->not('null'));
940
     * </code>
941
     *
942
     * @param string $expression
943
     *
944
     * @return string The logical expression.
945
     */
946
    public function getNotExpression($expression)
947
    {
948
        return 'NOT(' . $expression . ')';
949
    }
950
951
    /**
952
     * Returns the SQL that checks if an expression is null.
953
     *
954
     * @param string $expression The expression that should be compared to null.
955
     *
956
     * @return string The logical expression.
957
     */
958 64534
    public function getIsNullExpression($expression)
959
    {
960 64534
        return $expression . ' IS NULL';
961
    }
962
963
    /**
964
     * Returns the SQL that checks if an expression is not null.
965
     *
966
     * @param string $expression The expression that should be compared to null.
967
     *
968
     * @return string The logical expression.
969
     */
970
    public function getIsNotNullExpression($expression)
971
    {
972
        return $expression . ' IS NOT NULL';
973
    }
974
975
    /**
976
     * Returns the SQL that checks if an expression evaluates to a value between two values.
977
     *
978
     * The parameter $expression is checked if it is between $value1 and $value2.
979
     *
980
     * Note: There is a slight difference in the way BETWEEN works on some databases.
981
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
982
     * independence you should avoid using between().
983
     *
984
     * @param string $expression The value to compare to.
985
     * @param string $value1     The lower value to compare with.
986
     * @param string $value2     The higher value to compare with.
987
     *
988
     * @return string The logical expression.
989
     */
990
    public function getBetweenExpression($expression, $value1, $value2)
991
    {
992
        return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2;
993
    }
994
995
    /**
996
     * Returns the SQL to get the arccosine of a value.
997
     *
998
     * @param string $value
999
     *
1000
     * @return string
1001
     */
1002
    public function getAcosExpression($value)
1003
    {
1004
        return 'ACOS(' . $value . ')';
1005
    }
1006
1007
    /**
1008
     * Returns the SQL to get the sine of a value.
1009
     *
1010
     * @param string $value
1011
     *
1012
     * @return string
1013
     */
1014
    public function getSinExpression($value)
1015
    {
1016
        return 'SIN(' . $value . ')';
1017
    }
1018
1019
    /**
1020
     * Returns the SQL to get the PI value.
1021
     *
1022
     * @return string
1023
     */
1024
    public function getPiExpression()
1025
    {
1026
        return 'PI()';
1027
    }
1028
1029
    /**
1030
     * Returns the SQL to get the cosine of a value.
1031
     *
1032
     * @param string $value
1033
     *
1034
     * @return string
1035
     */
1036
    public function getCosExpression($value)
1037
    {
1038
        return 'COS(' . $value . ')';
1039
    }
1040
1041
    /**
1042
     * Returns the SQL to calculate the difference in days between the two passed dates.
1043
     *
1044
     * Computes diff = date1 - date2.
1045
     *
1046
     * @param string $date1
1047
     * @param string $date2
1048
     *
1049
     * @return string
1050
     *
1051
     * @throws DBALException If not supported on this platform.
1052
     */
1053
    public function getDateDiffExpression($date1, $date2)
0 ignored issues
show
Unused Code introduced by
The parameter $date2 is not used and could be removed. ( Ignorable by Annotation )

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

1053
    public function getDateDiffExpression($date1, /** @scrutinizer ignore-unused */ $date2)

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

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

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

1053
    public function getDateDiffExpression(/** @scrutinizer ignore-unused */ $date1, $date2)

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

Loading history...
1054
    {
1055
        throw DBALException::notSupported(__METHOD__);
1056
    }
1057
1058
    /**
1059
     * Returns the SQL to add the number of given seconds to a date.
1060
     *
1061
     * @param string $date
1062
     * @param int    $seconds
1063
     *
1064
     * @return string
1065
     *
1066
     * @throws DBALException If not supported on this platform.
1067
     */
1068 62745
    public function getDateAddSecondsExpression($date, $seconds)
1069
    {
1070 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND);
1071
    }
1072
1073
    /**
1074
     * Returns the SQL to subtract the number of given seconds from a date.
1075
     *
1076
     * @param string $date
1077
     * @param int    $seconds
1078
     *
1079
     * @return string
1080
     *
1081
     * @throws DBALException If not supported on this platform.
1082
     */
1083 62745
    public function getDateSubSecondsExpression($date, $seconds)
1084
    {
1085 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND);
1086
    }
1087
1088
    /**
1089
     * Returns the SQL to add the number of given minutes to a date.
1090
     *
1091
     * @param string $date
1092
     * @param int    $minutes
1093
     *
1094
     * @return string
1095
     *
1096
     * @throws DBALException If not supported on this platform.
1097
     */
1098 62745
    public function getDateAddMinutesExpression($date, $minutes)
1099
    {
1100 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE);
1101
    }
1102
1103
    /**
1104
     * Returns the SQL to subtract the number of given minutes from a date.
1105
     *
1106
     * @param string $date
1107
     * @param int    $minutes
1108
     *
1109
     * @return string
1110
     *
1111
     * @throws DBALException If not supported on this platform.
1112
     */
1113 62745
    public function getDateSubMinutesExpression($date, $minutes)
1114
    {
1115 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE);
1116
    }
1117
1118
    /**
1119
     * Returns the SQL to add the number of given hours to a date.
1120
     *
1121
     * @param string $date
1122
     * @param int    $hours
1123
     *
1124
     * @return string
1125
     *
1126
     * @throws DBALException If not supported on this platform.
1127
     */
1128 62745
    public function getDateAddHourExpression($date, $hours)
1129
    {
1130 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR);
1131
    }
1132
1133
    /**
1134
     * Returns the SQL to subtract the number of given hours to a date.
1135
     *
1136
     * @param string $date
1137
     * @param int    $hours
1138
     *
1139
     * @return string
1140
     *
1141
     * @throws DBALException If not supported on this platform.
1142
     */
1143 62745
    public function getDateSubHourExpression($date, $hours)
1144
    {
1145 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR);
1146
    }
1147
1148
    /**
1149
     * Returns the SQL to add the number of given days to a date.
1150
     *
1151
     * @param string $date
1152
     * @param int    $days
1153
     *
1154
     * @return string
1155
     *
1156
     * @throws DBALException If not supported on this platform.
1157
     */
1158 62749
    public function getDateAddDaysExpression($date, $days)
1159
    {
1160 62749
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY);
1161
    }
1162
1163
    /**
1164
     * Returns the SQL to subtract the number of given days to a date.
1165
     *
1166
     * @param string $date
1167
     * @param int    $days
1168
     *
1169
     * @return string
1170
     *
1171
     * @throws DBALException If not supported on this platform.
1172
     */
1173 62745
    public function getDateSubDaysExpression($date, $days)
1174
    {
1175 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY);
1176
    }
1177
1178
    /**
1179
     * Returns the SQL to add the number of given weeks to a date.
1180
     *
1181
     * @param string $date
1182
     * @param int    $weeks
1183
     *
1184
     * @return string
1185
     *
1186
     * @throws DBALException If not supported on this platform.
1187
     */
1188 62745
    public function getDateAddWeeksExpression($date, $weeks)
1189
    {
1190 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK);
1191
    }
1192
1193
    /**
1194
     * Returns the SQL to subtract the number of given weeks from a date.
1195
     *
1196
     * @param string $date
1197
     * @param int    $weeks
1198
     *
1199
     * @return string
1200
     *
1201
     * @throws DBALException If not supported on this platform.
1202
     */
1203 62745
    public function getDateSubWeeksExpression($date, $weeks)
1204
    {
1205 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK);
1206
    }
1207
1208
    /**
1209
     * Returns the SQL to add the number of given months to a date.
1210
     *
1211
     * @param string $date
1212
     * @param int    $months
1213
     *
1214
     * @return string
1215
     *
1216
     * @throws DBALException If not supported on this platform.
1217
     */
1218 62745
    public function getDateAddMonthExpression($date, $months)
1219
    {
1220 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH);
1221
    }
1222
1223
    /**
1224
     * Returns the SQL to subtract the number of given months to a date.
1225
     *
1226
     * @param string $date
1227
     * @param int    $months
1228
     *
1229
     * @return string
1230
     *
1231
     * @throws DBALException If not supported on this platform.
1232
     */
1233 62745
    public function getDateSubMonthExpression($date, $months)
1234
    {
1235 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH);
1236
    }
1237
1238
    /**
1239
     * Returns the SQL to add the number of given quarters to a date.
1240
     *
1241
     * @param string $date
1242
     * @param int    $quarters
1243
     *
1244
     * @return string
1245
     *
1246
     * @throws DBALException If not supported on this platform.
1247
     */
1248 62745
    public function getDateAddQuartersExpression($date, $quarters)
1249
    {
1250 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER);
1251
    }
1252
1253
    /**
1254
     * Returns the SQL to subtract the number of given quarters from a date.
1255
     *
1256
     * @param string $date
1257
     * @param int    $quarters
1258
     *
1259
     * @return string
1260
     *
1261
     * @throws DBALException If not supported on this platform.
1262
     */
1263 62745
    public function getDateSubQuartersExpression($date, $quarters)
1264
    {
1265 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER);
1266
    }
1267
1268
    /**
1269
     * Returns the SQL to add the number of given years to a date.
1270
     *
1271
     * @param string $date
1272
     * @param int    $years
1273
     *
1274
     * @return string
1275
     *
1276
     * @throws DBALException If not supported on this platform.
1277
     */
1278 62745
    public function getDateAddYearsExpression($date, $years)
1279
    {
1280 62745
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR);
1281
    }
1282
1283
    /**
1284
     * Returns the SQL to subtract the number of given years from a date.
1285
     *
1286
     * @param string $date
1287
     * @param int    $years
1288
     *
1289
     * @return string
1290
     *
1291
     * @throws DBALException If not supported on this platform.
1292
     */
1293 62745
    public function getDateSubYearsExpression($date, $years)
1294
    {
1295 62745
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR);
1296
    }
1297
1298
    /**
1299
     * Returns the SQL for a date arithmetic expression.
1300
     *
1301
     * @param string $date     The column or literal representing a date to perform the arithmetic operation on.
1302
     * @param string $operator The arithmetic operator (+ or -).
1303
     * @param int    $interval The interval that shall be calculated into the date.
1304
     * @param string $unit     The unit of the interval that shall be calculated into the date.
1305
     *                         One of the DATE_INTERVAL_UNIT_* constants.
1306
     *
1307
     * @return string
1308
     *
1309
     * @throws DBALException If not supported on this platform.
1310
     */
1311
    protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit)
0 ignored issues
show
Unused Code introduced by
The parameter $interval is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1312
    {
1313
        throw DBALException::notSupported(__METHOD__);
1314
    }
1315
1316
    /**
1317
     * Returns the SQL bit AND comparison expression.
1318
     *
1319
     * @param string $value1
1320
     * @param string $value2
1321
     *
1322
     * @return string
1323
     */
1324 62439
    public function getBitAndComparisonExpression($value1, $value2)
1325
    {
1326 62439
        return '(' . $value1 . ' & ' . $value2 . ')';
1327
    }
1328
1329
    /**
1330
     * Returns the SQL bit OR comparison expression.
1331
     *
1332
     * @param string $value1
1333
     * @param string $value2
1334
     *
1335
     * @return string
1336
     */
1337 60273
    public function getBitOrComparisonExpression($value1, $value2)
1338
    {
1339 60273
        return '(' . $value1 . ' | ' . $value2 . ')';
1340
    }
1341
1342
    /**
1343
     * Returns the FOR UPDATE expression.
1344
     *
1345
     * @return string
1346
     */
1347 49658
    public function getForUpdateSQL()
1348
    {
1349 49658
        return 'FOR UPDATE';
1350
    }
1351
1352
    /**
1353
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1354
     *
1355
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1356
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1357
     *                             be appended to the FROM clause.
1358
     *
1359
     * @return string
1360
     */
1361 52021
    public function appendLockHint($fromClause, $lockMode)
0 ignored issues
show
Unused Code introduced by
The parameter $lockMode is not used and could be removed. ( Ignorable by Annotation )

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

1361
    public function appendLockHint($fromClause, /** @scrutinizer ignore-unused */ $lockMode)

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

Loading history...
1362
    {
1363 52021
        return $fromClause;
1364
    }
1365
1366
    /**
1367
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1368
     *
1369
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1370
     * vendors allow to lighten this constraint up to be a real read lock.
1371
     *
1372
     * @return string
1373
     */
1374
    public function getReadLockSQL()
1375
    {
1376
        return $this->getForUpdateSQL();
1377
    }
1378
1379
    /**
1380
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1381
     *
1382
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1383
     *
1384
     * @return string
1385
     */
1386 56750
    public function getWriteLockSQL()
1387
    {
1388 56750
        return $this->getForUpdateSQL();
1389
    }
1390
1391
    /**
1392
     * Returns the SQL snippet to drop an existing database.
1393
     *
1394
     * @param string $database The name of the database that should be dropped.
1395
     *
1396
     * @return string
1397
     */
1398 49551
    public function getDropDatabaseSQL($database)
1399
    {
1400 49551
        return 'DROP DATABASE ' . $database;
1401
    }
1402
1403
    /**
1404
     * Returns the SQL snippet to drop an existing table.
1405
     *
1406
     * @param Table|string $table
1407
     *
1408
     * @return string
1409
     *
1410
     * @throws InvalidArgumentException
1411
     */
1412 63974
    public function getDropTableSQL($table)
1413
    {
1414 63974
        $tableArg = $table;
1415
1416 63974
        if ($table instanceof Table) {
1417 7043
            $table = $table->getQuotedName($this);
1418
        }
1419
1420 63974
        if (! is_string($table)) {
0 ignored issues
show
introduced by
The condition is_string($table) is always true.
Loading history...
1421
            throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1422
        }
1423
1424 63974
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1425 56911
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1426 56911
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1427
1428 56911
            if ($eventArgs->isDefaultPrevented()) {
1429
                $sql = $eventArgs->getSql();
1430
1431
                if ($sql === null) {
1432
                    throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL');
1433
                }
1434
1435
                return $sql;
1436
            }
1437
        }
1438
1439 63974
        return 'DROP TABLE ' . $table;
1440
    }
1441
1442
    /**
1443
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1444
     *
1445
     * @param Table|string $table
1446
     *
1447
     * @return string
1448
     */
1449 25995
    public function getDropTemporaryTableSQL($table)
1450
    {
1451 25995
        return $this->getDropTableSQL($table);
1452
    }
1453
1454
    /**
1455
     * Returns the SQL to drop an index from a table.
1456
     *
1457
     * @param Index|string $index
1458
     * @param Table|string $table
1459
     *
1460
     * @return string
1461
     *
1462
     * @throws InvalidArgumentException
1463
     */
1464 49381
    public function getDropIndexSQL($index, $table = null)
1465
    {
1466 49381
        if ($index instanceof Index) {
1467 49352
            $index = $index->getQuotedName($this);
1468 21793
        } elseif (! is_string($index)) {
0 ignored issues
show
introduced by
The condition is_string($index) is always true.
Loading history...
1469
            throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1470
        }
1471
1472 49381
        return 'DROP INDEX ' . $index;
1473
    }
1474
1475
    /**
1476
     * Returns the SQL to drop a constraint.
1477
     *
1478
     * @param Constraint|string $constraint
1479
     * @param Table|string      $table
1480
     *
1481
     * @return string
1482
     */
1483 57589
    public function getDropConstraintSQL($constraint, $table)
1484
    {
1485 57589
        if (! $constraint instanceof Constraint) {
1486 56376
            $constraint = new Identifier($constraint);
1487
        }
1488
1489 57589
        if (! $table instanceof Table) {
1490 57589
            $table = new Identifier($table);
1491
        }
1492
1493 57589
        $constraint = $constraint->getQuotedName($this);
1494 57589
        $table      = $table->getQuotedName($this);
1495
1496 57589
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1497
    }
1498
1499
    /**
1500
     * Returns the SQL to drop a foreign key.
1501
     *
1502
     * @param ForeignKeyConstraint|string $foreignKey
1503
     * @param Table|string                $table
1504
     *
1505
     * @return string
1506
     */
1507 58676
    public function getDropForeignKeySQL($foreignKey, $table)
1508
    {
1509 58676
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1510 56141
            $foreignKey = new Identifier($foreignKey);
1511
        }
1512
1513 58676
        if (! $table instanceof Table) {
1514 58676
            $table = new Identifier($table);
1515
        }
1516
1517 58676
        $foreignKey = $foreignKey->getQuotedName($this);
1518 58676
        $table      = $table->getQuotedName($this);
1519
1520 58676
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1521
    }
1522
1523
    /**
1524
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1525
     * on this platform.
1526
     *
1527
     * @param int $createFlags
1528
     *
1529
     * @return string[] The sequence of SQL statements.
1530
     *
1531
     * @throws DBALException
1532
     * @throws InvalidArgumentException
1533
     */
1534 64508
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1535
    {
1536 64508
        if (! is_int($createFlags)) {
0 ignored issues
show
introduced by
The condition is_int($createFlags) is always true.
Loading history...
1537
            throw new InvalidArgumentException('Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.');
1538
        }
1539
1540 64508
        if (count($table->getColumns()) === 0) {
1541 57211
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1542
        }
1543
1544 64472
        $tableName                    = $table->getQuotedName($this);
1545 64472
        $options                      = $table->getOptions();
1546 64472
        $options['uniqueConstraints'] = [];
1547 64472
        $options['indexes']           = [];
1548 64472
        $options['primary']           = [];
1549
1550 64472
        if (($createFlags&self::CREATE_INDEXES) > 0) {
1551 64426
            foreach ($table->getIndexes() as $index) {
1552
                /** @var $index Index */
1553 64174
                if ($index->isPrimary()) {
1554 64042
                    $options['primary']       = $index->getQuotedColumns($this);
1555 64042
                    $options['primary_index'] = $index;
1556
                } else {
1557 62998
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1558
                }
1559
            }
1560
        }
1561
1562 64472
        $columnSql = [];
1563 64472
        $columns   = [];
1564
1565 64472
        foreach ($table->getColumns() as $column) {
1566 64472
            if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) {
1567 56936
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1568 56936
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1569
1570 56936
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1571
1572 56936
                if ($eventArgs->isDefaultPrevented()) {
1573
                    continue;
1574
                }
1575
            }
1576
1577 64472
            $columnData            = $column->toArray();
1578 64472
            $columnData['name']    = $column->getQuotedName($this);
1579 64472
            $columnData['version'] = $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false;
1580 64472
            $columnData['comment'] = $this->getColumnComment($column);
1581
1582 64472
            if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) {
1583 63608
                $columnData['length'] = 255;
1584
            }
1585
1586 64472
            if (in_array($column->getName(), $options['primary'])) {
1587 64002
                $columnData['primary'] = true;
1588
            }
1589
1590 64472
            $columns[$columnData['name']] = $columnData;
1591
        }
1592
1593 64472
        if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
1594 64020
            $options['foreignKeys'] = [];
1595 64020
            foreach ($table->getForeignKeys() as $fkConstraint) {
1596 62485
                $options['foreignKeys'][] = $fkConstraint;
1597
            }
1598
        }
1599
1600 64472
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
1601 56936
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1602 56936
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1603
1604 56936
            if ($eventArgs->isDefaultPrevented()) {
1605
                return array_merge($eventArgs->getSql(), $columnSql);
1606
            }
1607
        }
1608
1609 64472
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1610 64472
        if ($this->supportsCommentOnStatement()) {
1611 60454
            foreach ($table->getColumns() as $column) {
1612 60454
                $comment = $this->getColumnComment($column);
1613
1614 60454
                if ($comment === null || $comment === '') {
1615 60420
                    continue;
1616
                }
1617
1618 58219
                $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1619
            }
1620
        }
1621
1622 64472
        return array_merge($sql, $columnSql);
1623
    }
1624
1625
    /**
1626
     * @param string      $tableName
1627
     * @param string      $columnName
1628
     * @param string|null $comment
1629
     *
1630
     * @return string
1631
     */
1632 57117
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
1633
    {
1634 57117
        $tableName  = new Identifier($tableName);
1635 57117
        $columnName = new Identifier($columnName);
1636
1637 57117
        return sprintf(
1638 131
            'COMMENT ON COLUMN %s.%s IS %s',
1639 57117
            $tableName->getQuotedName($this),
1640 57117
            $columnName->getQuotedName($this),
1641 57117
            $this->quoteStringLiteral((string) $comment)
1642
        );
1643
    }
1644
1645
    /**
1646
     * Returns the SQL to create inline comment on a column.
1647
     *
1648
     * @param string $comment
1649
     *
1650
     * @return string
1651
     *
1652
     * @throws DBALException If not supported on this platform.
1653
     */
1654 58857
    public function getInlineColumnCommentSQL($comment)
1655
    {
1656 58857
        if (! $this->supportsInlineColumnComments()) {
1657 56028
            throw DBALException::notSupported(__METHOD__);
1658
        }
1659
1660 57949
        return 'COMMENT ' . $this->quoteStringLiteral($comment);
1661
    }
1662
1663
    /**
1664
     * Returns the SQL used to create a table.
1665
     *
1666
     * @param string    $tableName
1667
     * @param mixed[][] $columns
1668
     * @param mixed[]   $options
1669
     *
1670
     * @return string[]
1671
     */
1672 58627
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1673
    {
1674 58627
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1675
1676 58627
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1677
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1678
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1679
            }
1680
        }
1681
1682 58627
        if (isset($options['primary']) && ! empty($options['primary'])) {
1683 58501
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1684
        }
1685
1686 58627
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1687
            foreach ($options['indexes'] as $index => $definition) {
1688
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1689
            }
1690
        }
1691
1692 58627
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1693
1694 58627
        $check = $this->getCheckDeclarationSQL($columns);
1695 58627
        if (! empty($check)) {
1696 58077
            $query .= ', ' . $check;
1697
        }
1698 58627
        $query .= ')';
1699
1700 58627
        $sql[] = $query;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sql was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sql = array(); before regardless.
Loading history...
1701
1702 58627
        if (isset($options['foreignKeys'])) {
1703 58545
            foreach ((array) $options['foreignKeys'] as $definition) {
1704 58224
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1705
            }
1706
        }
1707
1708 58627
        return $sql;
1709
    }
1710
1711
    /**
1712
     * @return string
1713
     */
1714 51975
    public function getCreateTemporaryTableSnippetSQL()
1715
    {
1716 51975
        return 'CREATE TEMPORARY TABLE';
1717
    }
1718
1719
    /**
1720
     * Returns the SQL to create a sequence on this platform.
1721
     *
1722
     * @return string
1723
     *
1724
     * @throws DBALException If not supported on this platform.
1725
     */
1726
    public function getCreateSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

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

1726
    public function getCreateSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

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

Loading history...
1727
    {
1728
        throw DBALException::notSupported(__METHOD__);
1729
    }
1730
1731
    /**
1732
     * Returns the SQL to change a sequence on this platform.
1733
     *
1734
     * @return string
1735
     *
1736
     * @throws DBALException If not supported on this platform.
1737
     */
1738
    public function getAlterSequenceSQL(Sequence $sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

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

1738
    public function getAlterSequenceSQL(/** @scrutinizer ignore-unused */ Sequence $sequence)

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

Loading history...
1739
    {
1740
        throw DBALException::notSupported(__METHOD__);
1741
    }
1742
1743
    /**
1744
     * Returns the SQL to create a constraint on a table on this platform.
1745
     *
1746
     * @param Table|string $table
1747
     *
1748
     * @return string
1749
     *
1750
     * @throws InvalidArgumentException
1751
     */
1752 57101
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1753
    {
1754 57101
        if ($table instanceof Table) {
1755
            $table = $table->getQuotedName($this);
1756
        }
1757
1758 57101
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1759
1760 57101
        $columnList = '(' . implode(', ', $constraint->getQuotedColumns($this)) . ')';
1761
1762 57101
        $referencesClause = '';
1763 57101
        if ($constraint instanceof Index) {
1764 57101
            if ($constraint->isPrimary()) {
1765 57101
                $query .= ' PRIMARY KEY';
1766 57051
            } elseif ($constraint->isUnique()) {
1767 57051
                $query .= ' UNIQUE';
1768
            } else {
1769
                throw new InvalidArgumentException(
1770 57101
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1771
                );
1772
            }
1773 57051
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1774 57051
            $query .= ' FOREIGN KEY';
1775
1776 57051
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1777 57051
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1778
        }
1779 57101
        $query .= ' ' . $columnList . $referencesClause;
1780
1781 57101
        return $query;
1782
    }
1783
1784
    /**
1785
     * Returns the SQL to create an index on a table on this platform.
1786
     *
1787
     * @param Table|string $table The name of the table on which the index is to be created.
1788
     *
1789
     * @return string
1790
     *
1791
     * @throws InvalidArgumentException
1792
     */
1793 61511
    public function getCreateIndexSQL(Index $index, $table)
1794
    {
1795 61511
        if ($table instanceof Table) {
1796 60517
            $table = $table->getQuotedName($this);
1797
        }
1798 61511
        $name    = $index->getQuotedName($this);
1799 61511
        $columns = $index->getColumns();
1800
1801 61511
        if (count($columns) === 0) {
1802
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
1803
        }
1804
1805 61511
        if ($index->isPrimary()) {
1806 55242
            return $this->getCreatePrimaryKeySQL($index, $table);
1807
        }
1808
1809 61473
        $query  = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1810 61473
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index);
1811
1812 61473
        return $query;
1813
    }
1814
1815
    /**
1816
     * Adds condition for partial index.
1817
     *
1818
     * @return string
1819
     */
1820 62872
    protected function getPartialIndexSQL(Index $index)
1821
    {
1822 62872
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1823 47537
            return ' WHERE ' . $index->getOption('where');
1824
        }
1825
1826 62862
        return '';
1827
    }
1828
1829
    /**
1830
     * Adds additional flags for index generation.
1831
     *
1832
     * @return string
1833
     */
1834 59805
    protected function getCreateIndexSQLFlags(Index $index)
1835
    {
1836 59805
        return $index->isUnique() ? 'UNIQUE ' : '';
1837
    }
1838
1839
    /**
1840
     * Returns the SQL to create an unnamed primary key constraint.
1841
     *
1842
     * @param Table|string $table
1843
     *
1844
     * @return string
1845
     */
1846 58009
    public function getCreatePrimaryKeySQL(Index $index, $table)
1847
    {
1848 58009
        if ($table instanceof Table) {
1849
            $table = $table->getQuotedName($this);
1850
        }
1851
1852 58009
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')';
1853
    }
1854
1855
    /**
1856
     * Returns the SQL to create a named schema.
1857
     *
1858
     * @param string $schemaName
1859
     *
1860
     * @return string
1861
     *
1862
     * @throws DBALException If not supported on this platform.
1863
     */
1864 56420
    public function getCreateSchemaSQL($schemaName)
0 ignored issues
show
Unused Code introduced by
The parameter $schemaName is not used and could be removed. ( Ignorable by Annotation )

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

1864
    public function getCreateSchemaSQL(/** @scrutinizer ignore-unused */ $schemaName)

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

Loading history...
1865
    {
1866 56420
        throw DBALException::notSupported(__METHOD__);
1867
    }
1868
1869
    /**
1870
     * Quotes a string so that it can be safely used as a table or column name,
1871
     * even if it is a reserved word of the platform. This also detects identifier
1872
     * chains separated by dot and quotes them independently.
1873
     *
1874
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1875
     * you SHOULD use them. In general, they end up causing way more
1876
     * problems than they solve.
1877
     *
1878
     * @param string $str The identifier name to be quoted.
1879
     *
1880
     * @return string The quoted identifier string.
1881
     */
1882 64168
    public function quoteIdentifier($str)
1883
    {
1884 64168
        if (strpos($str, '.') !== false) {
1885 58160
            $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str));
1886
1887 58160
            return implode('.', $parts);
1888
        }
1889
1890 64168
        return $this->quoteSingleIdentifier($str);
1891
    }
1892
1893
    /**
1894
     * Quotes a single identifier (no dot chain separation).
1895
     *
1896
     * @param string $str The identifier name to be quoted.
1897
     *
1898
     * @return string The quoted identifier string.
1899
     */
1900 63742
    public function quoteSingleIdentifier($str)
1901
    {
1902 63742
        $c = $this->getIdentifierQuoteCharacter();
1903
1904 63742
        return $c . str_replace($c, $c . $c, $str) . $c;
1905
    }
1906
1907
    /**
1908
     * Returns the SQL to create a new foreign key.
1909
     *
1910
     * @param ForeignKeyConstraint $foreignKey The foreign key constraint.
1911
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
1912
     *
1913
     * @return string
1914
     */
1915 62504
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1916
    {
1917 62504
        if ($table instanceof Table) {
1918 2927
            $table = $table->getQuotedName($this);
1919
        }
1920
1921 62504
        return 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1922
    }
1923
1924
    /**
1925
     * Gets the SQL statements for altering an existing table.
1926
     *
1927
     * This method returns an array of SQL statements, since some platforms need several statements.
1928
     *
1929
     * @return string[]
1930
     *
1931
     * @throws DBALException If not supported on this platform.
1932
     */
1933
    public function getAlterTableSQL(TableDiff $diff)
1934
    {
1935
        throw DBALException::notSupported(__METHOD__);
1936
    }
1937
1938
    /**
1939
     * @param mixed[] $columnSql
1940
     *
1941
     * @return bool
1942
     */
1943 61557
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
1944
    {
1945 61557
        if ($this->_eventManager === null) {
1946 57110
            return false;
1947
        }
1948
1949 61397
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1950 61361
            return false;
1951
        }
1952
1953 56886
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1954 56886
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1955
1956 56886
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1957
1958 56886
        return $eventArgs->isDefaultPrevented();
1959
    }
1960
1961
    /**
1962
     * @param string[] $columnSql
1963
     *
1964
     * @return bool
1965
     */
1966 60618
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
1967
    {
1968 60618
        if ($this->_eventManager === null) {
1969 57064
            return false;
1970
        }
1971
1972 60504
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
1973 60468
            return false;
1974
        }
1975
1976 56886
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
1977 56886
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
1978
1979 56886
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1980
1981 56886
        return $eventArgs->isDefaultPrevented();
1982
    }
1983
1984
    /**
1985
     * @param string[] $columnSql
1986
     *
1987
     * @return bool
1988
     */
1989 61482
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
1990
    {
1991 61482
        if ($this->_eventManager === null) {
1992 58107
            return false;
1993
        }
1994
1995 61150
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
1996 61114
            return false;
1997
        }
1998
1999 56886
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
2000 56886
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
2001
2002 56886
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2003
2004 56886
        return $eventArgs->isDefaultPrevented();
2005
    }
2006
2007
    /**
2008
     * @param string   $oldColumnName
2009
     * @param string[] $columnSql
2010
     *
2011
     * @return bool
2012
     */
2013 60388
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
2014
    {
2015 60388
        if ($this->_eventManager === null) {
2016 56316
            return false;
2017
        }
2018
2019 60272
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
2020 57962
            return false;
2021
        }
2022
2023 56886
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
2024 56886
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
2025
2026 56886
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
2027
2028 56886
        return $eventArgs->isDefaultPrevented();
2029
    }
2030
2031
    /**
2032
     * @param string[] $sql
2033
     *
2034
     * @return bool
2035
     */
2036 62375
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
2037
    {
2038 62375
        if ($this->_eventManager === null) {
2039 58445
            return false;
2040
        }
2041
2042 61705
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
2043 61669
            return false;
2044
        }
2045
2046 56886
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
2047 56886
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
2048
2049 56886
        $sql = array_merge($sql, $eventArgs->getSql());
2050
2051 56886
        return $eventArgs->isDefaultPrevented();
2052
    }
2053
2054
    /**
2055
     * @return string[]
2056
     */
2057 62231
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
2058
    {
2059 62231
        $tableName = $diff->getName($this)->getQuotedName($this);
2060
2061 62231
        $sql = [];
2062 62231
        if ($this->supportsForeignKeyConstraints()) {
2063 62231
            foreach ($diff->removedForeignKeys as $foreignKey) {
2064 60201
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2065
            }
2066 62231
            foreach ($diff->changedForeignKeys as $foreignKey) {
2067 55965
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
2068
            }
2069
        }
2070
2071 62231
        foreach ($diff->removedIndexes as $index) {
2072 60670
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2073
        }
2074 62231
        foreach ($diff->changedIndexes as $index) {
2075 60261
            $sql[] = $this->getDropIndexSQL($index, $tableName);
2076
        }
2077
2078 62231
        return $sql;
2079
    }
2080
2081
    /**
2082
     * @return string[]
2083
     */
2084 62231
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
2085
    {
2086 62231
        $sql     = [];
2087 62231
        $newName = $diff->getNewName();
2088
2089 62231
        if ($newName !== false) {
2090 57339
            $tableName = $newName->getQuotedName($this);
2091
        } else {
2092 62161
            $tableName = $diff->getName($this)->getQuotedName($this);
2093
        }
2094
2095 62231
        if ($this->supportsForeignKeyConstraints()) {
2096 62231
            foreach ($diff->addedForeignKeys as $foreignKey) {
2097 60298
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2098
            }
2099
2100 62231
            foreach ($diff->changedForeignKeys as $foreignKey) {
2101 55965
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
2102
            }
2103
        }
2104
2105 62231
        foreach ($diff->addedIndexes as $index) {
2106 60242
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2107
        }
2108
2109 62231
        foreach ($diff->changedIndexes as $index) {
2110 60261
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
2111
        }
2112
2113 62231
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
2114 60441
            $oldIndexName = new Identifier($oldIndexName);
2115 60441
            $sql          = array_merge(
2116 60441
                $sql,
2117 60441
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
2118
            );
2119
        }
2120
2121 62231
        return $sql;
2122
    }
2123
2124
    /**
2125
     * Returns the SQL for renaming an index on a table.
2126
     *
2127
     * @param string $oldIndexName The name of the index to rename from.
2128
     * @param Index  $index        The definition of the index to rename to.
2129
     * @param string $tableName    The table to rename the given index on.
2130
     *
2131
     * @return string[] The sequence of SQL statements for renaming the given index.
2132
     */
2133 56242
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
2134
    {
2135
        return [
2136 56242
            $this->getDropIndexSQL($oldIndexName, $tableName),
2137 56242
            $this->getCreateIndexSQL($index, $tableName),
2138
        ];
2139
    }
2140
2141
    /**
2142
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
2143
     *
2144
     * @deprecated
2145
     *
2146
     * @return string[]
2147
     */
2148
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
2149
    {
2150
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
2151
    }
2152
2153
    /**
2154
     * Gets declaration of a number of fields in bulk.
2155
     *
2156
     * @param mixed[][] $fields A multidimensional associative array.
2157
     *                          The first dimension determines the field name, while the second
2158
     *                          dimension is keyed with the name of the properties
2159
     *                          of the field being declared as array indexes. Currently, the types
2160
     *                          of supported field properties are as follows:
2161
     *
2162
     *      length
2163
     *          Integer value that determines the maximum length of the text
2164
     *          field. If this argument is missing the field should be
2165
     *          declared to have the longest length allowed by the DBMS.
2166
     *
2167
     *      default
2168
     *          Text value to be used as default for this field.
2169
     *
2170
     *      notnull
2171
     *          Boolean flag that indicates whether this field is constrained
2172
     *          to not be set to null.
2173
     *      charset
2174
     *          Text value with the default CHARACTER SET for this field.
2175
     *      collation
2176
     *          Text value with the default COLLATION for this field.
2177
     *      unique
2178
     *          unique constraint
2179
     *
2180
     * @return string
2181
     */
2182 64472
    public function getColumnDeclarationListSQL(array $fields)
2183
    {
2184 64472
        $queryFields = [];
2185
2186 64472
        foreach ($fields as $fieldName => $field) {
2187 64472
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2188
        }
2189
2190 64472
        return implode(', ', $queryFields);
2191
    }
2192
2193
    /**
2194
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2195
     * field to be used in statements like CREATE TABLE.
2196
     *
2197
     * @param string  $name  The name the field to be declared.
2198
     * @param mixed[] $field An associative array with the name of the properties
2199
     *                       of the field being declared as array indexes. Currently, the types
2200
     *                       of supported field properties are as follows:
2201
     *
2202
     *      length
2203
     *          Integer value that determines the maximum length of the text
2204
     *          field. If this argument is missing the field should be
2205
     *          declared to have the longest length allowed by the DBMS.
2206
     *
2207
     *      default
2208
     *          Text value to be used as default for this field.
2209
     *
2210
     *      notnull
2211
     *          Boolean flag that indicates whether this field is constrained
2212
     *          to not be set to null.
2213
     *      charset
2214
     *          Text value with the default CHARACTER SET for this field.
2215
     *      collation
2216
     *          Text value with the default COLLATION for this field.
2217
     *      unique
2218
     *          unique constraint
2219
     *      check
2220
     *          column check constraint
2221
     *      columnDefinition
2222
     *          a string that defines the complete column
2223
     *
2224
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2225
     */
2226 63942
    public function getColumnDeclarationSQL($name, array $field)
2227
    {
2228 63942
        if (isset($field['columnDefinition'])) {
2229 58807
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2230
        } else {
2231 63914
            $default = $this->getDefaultValueDeclarationSQL($field);
2232
2233 63914
            $charset = isset($field['charset']) && $field['charset'] ?
2234 63914
                ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2235
2236 63914
            $collation = isset($field['collation']) && $field['collation'] ?
2237 63914
                ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2238
2239 63914
            $notnull = isset($field['notnull']) && $field['notnull'] ? ' NOT NULL' : '';
2240
2241 63914
            $unique = isset($field['unique']) && $field['unique'] ?
2242 63914
                ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2243
2244 63914
            $check = isset($field['check']) && $field['check'] ?
2245 63914
                ' ' . $field['check'] : '';
2246
2247 63914
            $typeDecl  = $field['type']->getSQLDeclaration($field, $this);
2248 63914
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2249
2250 63914
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2251 58180
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2252
            }
2253
        }
2254
2255 63942
        return $name . ' ' . $columnDef;
2256
    }
2257
2258
    /**
2259
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2260
     *
2261
     * @param mixed[] $columnDef
2262
     *
2263
     * @return string
2264
     */
2265 61201
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2266
    {
2267 61201
        $columnDef['precision'] = ! isset($columnDef['precision']) || empty($columnDef['precision'])
2268 61201
            ? 10 : $columnDef['precision'];
2269 61201
        $columnDef['scale']     = ! isset($columnDef['scale']) || empty($columnDef['scale'])
2270 61201
            ? 0 : $columnDef['scale'];
2271
2272 61201
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2273
    }
2274
2275
    /**
2276
     * Obtains DBMS specific SQL code portion needed to set a default value
2277
     * declaration to be used in statements like CREATE TABLE.
2278
     *
2279
     * @param mixed[] $field The field definition array.
2280
     *
2281
     * @return string DBMS specific SQL code portion needed to set a default value.
2282
     */
2283 64727
    public function getDefaultValueDeclarationSQL($field)
2284
    {
2285 64727
        if (! isset($field['default'])) {
2286 64162
            return empty($field['notnull']) ? ' DEFAULT NULL' : '';
2287
        }
2288
2289 62303
        $default = $field['default'];
2290
2291 62303
        if (! isset($field['type'])) {
2292 14324
            return " DEFAULT '" . $default . "'";
2293
        }
2294
2295 62279
        if ($default instanceof Expression) {
2296 56736
            return ' DEFAULT ' . $default;
2297
        }
2298
2299 62243
        $type = $field['type'];
2300
2301 62243
        if ($type instanceof Types\PhpIntegerMappingType) {
2302 61553
            return ' DEFAULT ' . $default;
2303
        }
2304
2305 62185
        if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
2306 61981
            return ' DEFAULT ' . $this->getCurrentTimestampSQL();
2307
        }
2308
2309 61873
        if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
2310 36951
            return ' DEFAULT ' . $this->getCurrentTimeSQL();
2311
        }
2312
2313 61873
        if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
2314 59660
            return ' DEFAULT ' . $this->getCurrentDateSQL();
2315
        }
2316
2317 61604
        if ($type instanceof Types\BooleanType) {
2318 61498
            return " DEFAULT '" . $this->convertBooleans($default) . "'";
0 ignored issues
show
Bug introduced by
Are you sure $this->convertBooleans($default) of type array|integer|mixed can be used in concatenation? ( Ignorable by Annotation )

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

2318
            return " DEFAULT '" . /** @scrutinizer ignore-type */ $this->convertBooleans($default) . "'";
Loading history...
2319
        }
2320
2321 61575
        return ' DEFAULT ' . $this->quoteStringLiteral($default);
2322
    }
2323
2324
    /**
2325
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2326
     * declaration to be used in statements like CREATE TABLE.
2327
     *
2328
     * @param string[]|mixed[][] $definition The check definition.
2329
     *
2330
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2331
     */
2332 59171
    public function getCheckDeclarationSQL(array $definition)
2333
    {
2334 59171
        $constraints = [];
2335 59171
        foreach ($definition as $field => $def) {
2336 59171
            if (is_string($def)) {
2337
                $constraints[] = 'CHECK (' . $def . ')';
2338
            } else {
2339 59171
                if (isset($def['min'])) {
2340 58085
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2341
                }
2342
2343 59171
                if (isset($def['max'])) {
2344 58597
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2345
                }
2346
            }
2347
        }
2348
2349 59171
        return implode(', ', $constraints);
2350
    }
2351
2352
    /**
2353
     * Obtains DBMS specific SQL code portion needed to set a unique
2354
     * constraint declaration to be used in statements like CREATE TABLE.
2355
     *
2356
     * @param string $name  The name of the unique constraint.
2357
     * @param Index  $index The index definition.
2358
     *
2359
     * @return string DBMS specific SQL code portion needed to set a constraint.
2360
     *
2361
     * @throws InvalidArgumentException
2362
     */
2363 57131
    public function getUniqueConstraintDeclarationSQL($name, Index $index)
2364
    {
2365 57131
        $columns = $index->getColumns();
2366 57131
        $name    = new Identifier($name);
2367
2368 57131
        if (count($columns) === 0) {
2369
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2370
        }
2371
2372 57131
        return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE ('
2373 57131
            . $this->getIndexFieldDeclarationListSQL($index)
2374 57131
            . ')' . $this->getPartialIndexSQL($index);
2375
    }
2376
2377
    /**
2378
     * Obtains DBMS specific SQL code portion needed to set an index
2379
     * declaration to be used in statements like CREATE TABLE.
2380
     *
2381
     * @param string $name  The name of the index.
2382
     * @param Index  $index The index definition.
2383
     *
2384
     * @return string DBMS specific SQL code portion needed to set an index.
2385
     *
2386
     * @throws InvalidArgumentException
2387
     */
2388 59608
    public function getIndexDeclarationSQL($name, Index $index)
2389
    {
2390 59608
        $columns = $index->getColumns();
2391 59608
        $name    = new Identifier($name);
2392
2393 59608
        if (count($columns) === 0) {
2394
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2395
        }
2396
2397 59608
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2398 59608
            . $this->getIndexFieldDeclarationListSQL($index)
2399 59608
            . ')' . $this->getPartialIndexSQL($index);
2400
    }
2401
2402
    /**
2403
     * Obtains SQL code portion needed to create a custom column,
2404
     * e.g. when a field has the "columnDefinition" keyword.
2405
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2406
     *
2407
     * @param mixed[] $columnDef
2408
     *
2409
     * @return string
2410
     */
2411 58815
    public function getCustomTypeDeclarationSQL(array $columnDef)
2412
    {
2413 58815
        return $columnDef['columnDefinition'];
2414
    }
2415
2416
    /**
2417
     * Obtains DBMS specific SQL code portion needed to set an index
2418
     * declaration to be used in statements like CREATE TABLE.
2419
     *
2420
     * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method
2421
     */
2422 63012
    public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string
2423
    {
2424 63012
        if ($columnsOrIndex instanceof Index) {
2425 62924
            return implode(', ', $columnsOrIndex->getQuotedColumns($this));
2426
        }
2427
2428 28675
        if (! is_array($columnsOrIndex)) {
0 ignored issues
show
introduced by
The condition is_array($columnsOrIndex) is always true.
Loading history...
2429
            throw new InvalidArgumentException('Fields argument should be an Index or array.');
2430
        }
2431
2432 28675
        $ret = [];
2433
2434 28675
        foreach ($columnsOrIndex as $column => $definition) {
2435 28675
            if (is_array($definition)) {
2436
                $ret[] = $column;
2437
            } else {
2438 28675
                $ret[] = $definition;
2439
            }
2440
        }
2441
2442 28675
        return implode(', ', $ret);
2443
    }
2444
2445
    /**
2446
     * Returns the required SQL string that fits between CREATE ... TABLE
2447
     * to create the table as a temporary table.
2448
     *
2449
     * Should be overridden in driver classes to return the correct string for the
2450
     * specific database type.
2451
     *
2452
     * The default is to return the string "TEMPORARY" - this will result in a
2453
     * SQL error for any database that does not support temporary tables, or that
2454
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2455
     *
2456
     * @return string The string required to be placed between "CREATE" and "TABLE"
2457
     *                to generate a temporary table, if possible.
2458
     */
2459
    public function getTemporaryTableSQL()
2460
    {
2461
        return 'TEMPORARY';
2462
    }
2463
2464
    /**
2465
     * Some vendors require temporary table names to be qualified specially.
2466
     *
2467
     * @param string $tableName
2468
     *
2469
     * @return string
2470
     */
2471 49612
    public function getTemporaryTableName($tableName)
2472
    {
2473 49612
        return $tableName;
2474
    }
2475
2476
    /**
2477
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2478
     * of a field declaration to be used in statements like CREATE TABLE.
2479
     *
2480
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2481
     *                of a field declaration.
2482
     */
2483 62655
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2484
    {
2485 62655
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2486 62631
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2487
2488 62631
        return $sql;
2489
    }
2490
2491
    /**
2492
     * Returns the FOREIGN KEY query section dealing with non-standard options
2493
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2494
     *
2495
     * @param ForeignKeyConstraint $foreignKey The foreign key definition.
2496
     *
2497
     * @return string
2498
     */
2499 62599
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2500
    {
2501 62599
        $query = '';
2502 62599
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2503 28133
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2504
        }
2505 62599
        if ($foreignKey->hasOption('onDelete')) {
2506 60039
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2507
        }
2508
2509 62599
        return $query;
2510
    }
2511
2512
    /**
2513
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2514
     *
2515
     * @param string $action The foreign key referential action.
2516
     *
2517
     * @return string
2518
     *
2519
     * @throws InvalidArgumentException If unknown referential action given.
2520
     */
2521 60802
    public function getForeignKeyReferentialActionSQL($action)
2522
    {
2523 60802
        $upper = strtoupper($action);
2524 60802
        switch ($upper) {
2525 242
            case 'CASCADE':
2526 164
            case 'SET NULL':
2527 122
            case 'NO ACTION':
2528 96
            case 'RESTRICT':
2529 68
            case 'SET DEFAULT':
2530 60768
                return $upper;
2531
            default:
2532 57409
                throw new InvalidArgumentException('Invalid foreign key action: ' . $upper);
2533
        }
2534
    }
2535
2536
    /**
2537
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2538
     * of a field declaration to be used in statements like CREATE TABLE.
2539
     *
2540
     * @return string
2541
     *
2542
     * @throws InvalidArgumentException
2543
     */
2544 62575
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2545
    {
2546 62575
        $sql = '';
2547 62575
        if (strlen($foreignKey->getName())) {
2548 62464
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2549
        }
2550 62575
        $sql .= 'FOREIGN KEY (';
2551
2552 62575
        if (count($foreignKey->getLocalColumns()) === 0) {
2553
            throw new InvalidArgumentException("Incomplete definition. 'local' required.");
2554
        }
2555 62575
        if (count($foreignKey->getForeignColumns()) === 0) {
2556
            throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
2557
        }
2558 62575
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2559
            throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2560
        }
2561
2562 62575
        return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this))
2563 62575
            . ') REFERENCES '
2564 62575
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2565 62575
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2566
    }
2567
2568
    /**
2569
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2570
     * of a field declaration to be used in statements like CREATE TABLE.
2571
     *
2572
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2573
     *                of a field declaration.
2574
     */
2575
    public function getUniqueFieldDeclarationSQL()
2576
    {
2577
        return 'UNIQUE';
2578
    }
2579
2580
    /**
2581
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2582
     * of a field declaration to be used in statements like CREATE TABLE.
2583
     *
2584
     * @param string $charset The name of the charset.
2585
     *
2586
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2587
     *                of a field declaration.
2588
     */
2589
    public function getColumnCharsetDeclarationSQL($charset)
0 ignored issues
show
Unused Code introduced by
The parameter $charset is not used and could be removed. ( Ignorable by Annotation )

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

2589
    public function getColumnCharsetDeclarationSQL(/** @scrutinizer ignore-unused */ $charset)

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

Loading history...
2590
    {
2591
        return '';
2592
    }
2593
2594
    /**
2595
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2596
     * of a field declaration to be used in statements like CREATE TABLE.
2597
     *
2598
     * @param string $collation The name of the collation.
2599
     *
2600
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2601
     *                of a field declaration.
2602
     */
2603 58983
    public function getColumnCollationDeclarationSQL($collation)
2604
    {
2605 58983
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2606
    }
2607
2608
    /**
2609
     * Whether the platform prefers sequences for ID generation.
2610
     * Subclasses should override this method to return TRUE if they prefer sequences.
2611
     *
2612
     * @return bool
2613
     */
2614 10
    public function prefersSequences()
2615
    {
2616 10
        return false;
2617
    }
2618
2619
    /**
2620
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2621
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2622
     *
2623
     * @return bool
2624
     */
2625 49931
    public function prefersIdentityColumns()
2626
    {
2627 49931
        return false;
2628
    }
2629
2630
    /**
2631
     * Some platforms need the boolean values to be converted.
2632
     *
2633
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2634
     *
2635
     * Note: if the input is not a boolean the original input might be returned.
2636
     *
2637
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2638
     * This method should handle the literal case
2639
     *
2640
     * @param mixed $item A boolean or an array of them.
2641
     *
2642
     * @return mixed A boolean database value or an array of them.
2643
     */
2644 59882
    public function convertBooleans($item)
2645
    {
2646 59882
        if (is_array($item)) {
2647
            foreach ($item as $k => $value) {
2648
                if (! is_bool($value)) {
2649
                    continue;
2650
                }
2651
2652
                $item[$k] = (int) $value;
2653
            }
2654 59882
        } elseif (is_bool($item)) {
2655 59880
            $item = (int) $item;
2656
        }
2657
2658 59882
        return $item;
2659
    }
2660
2661
    /**
2662
     * Some platforms have boolean literals that needs to be correctly converted
2663
     *
2664
     * The default conversion tries to convert value into bool "(bool)$item"
2665
     *
2666
     * @param mixed $item
2667
     *
2668
     * @return bool|null
2669
     */
2670 59069
    public function convertFromBoolean($item)
2671
    {
2672 59069
        return $item === null ? null: (bool) $item;
2673
    }
2674
2675
    /**
2676
     * This method should handle the prepared statements case. When there is no
2677
     * distinction, it's OK to use the same method.
2678
     *
2679
     * Note: if the input is not a boolean the original input might be returned.
2680
     *
2681
     * @param mixed $item A boolean or an array of them.
2682
     *
2683
     * @return mixed A boolean database value or an array of them.
2684
     */
2685 54586
    public function convertBooleansToDatabaseValue($item)
2686
    {
2687 54586
        return $this->convertBooleans($item);
2688
    }
2689
2690
    /**
2691
     * Returns the SQL specific for the platform to get the current date.
2692
     *
2693
     * @return string
2694
     */
2695 60393
    public function getCurrentDateSQL()
2696
    {
2697 60393
        return 'CURRENT_DATE';
2698
    }
2699
2700
    /**
2701
     * Returns the SQL specific for the platform to get the current time.
2702
     *
2703
     * @return string
2704
     */
2705 29570
    public function getCurrentTimeSQL()
2706
    {
2707 29570
        return 'CURRENT_TIME';
2708
    }
2709
2710
    /**
2711
     * Returns the SQL specific for the platform to get the current timestamp
2712
     *
2713
     * @return string
2714
     */
2715 61680
    public function getCurrentTimestampSQL()
2716
    {
2717 61680
        return 'CURRENT_TIMESTAMP';
2718
    }
2719
2720
    /**
2721
     * Returns the SQL for a given transaction isolation level Connection constant.
2722
     *
2723
     * @param int $level
2724
     *
2725
     * @return string
2726
     *
2727
     * @throws InvalidArgumentException
2728
     */
2729 55572
    protected function _getTransactionIsolationLevelSQL($level)
2730
    {
2731 22
        switch ($level) {
2732 55550
            case TransactionIsolationLevel::READ_UNCOMMITTED:
2733 55572
                return 'READ UNCOMMITTED';
2734 55550
            case TransactionIsolationLevel::READ_COMMITTED:
2735 55572
                return 'READ COMMITTED';
2736 55550
            case TransactionIsolationLevel::REPEATABLE_READ:
2737 55572
                return 'REPEATABLE READ';
2738 55550
            case TransactionIsolationLevel::SERIALIZABLE:
2739 55572
                return 'SERIALIZABLE';
2740
            default:
2741
                throw new InvalidArgumentException('Invalid isolation level:' . $level);
2742
        }
2743
    }
2744
2745
    /**
2746
     * @return string
2747
     *
2748
     * @throws DBALException If not supported on this platform.
2749
     */
2750 2432
    public function getListDatabasesSQL()
2751
    {
2752 2432
        throw DBALException::notSupported(__METHOD__);
2753
    }
2754
2755
    /**
2756
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2757
     *
2758
     * @return string
2759
     *
2760
     * @throws DBALException If not supported on this platform.
2761
     */
2762
    public function getListNamespacesSQL()
2763
    {
2764
        throw DBALException::notSupported(__METHOD__);
2765
    }
2766
2767
    /**
2768
     * @param string $database
2769
     *
2770
     * @return string
2771
     *
2772
     * @throws DBALException If not supported on this platform.
2773
     */
2774
    public function getListSequencesSQL($database)
2775
    {
2776
        throw DBALException::notSupported(__METHOD__);
2777
    }
2778
2779
    /**
2780
     * @param string $table
2781
     *
2782
     * @return string
2783
     *
2784
     * @throws DBALException If not supported on this platform.
2785
     */
2786
    public function getListTableConstraintsSQL($table)
2787
    {
2788
        throw DBALException::notSupported(__METHOD__);
2789
    }
2790
2791
    /**
2792
     * @param string      $table
2793
     * @param string|null $database
2794
     *
2795
     * @return string
2796
     *
2797
     * @throws DBALException If not supported on this platform.
2798
     */
2799
    public function getListTableColumnsSQL($table, $database = null)
2800
    {
2801
        throw DBALException::notSupported(__METHOD__);
2802
    }
2803
2804
    /**
2805
     * @return string
2806
     *
2807
     * @throws DBALException If not supported on this platform.
2808
     */
2809
    public function getListTablesSQL()
2810
    {
2811
        throw DBALException::notSupported(__METHOD__);
2812
    }
2813
2814
    /**
2815
     * @return string
2816
     *
2817
     * @throws DBALException If not supported on this platform.
2818
     */
2819
    public function getListUsersSQL()
2820
    {
2821
        throw DBALException::notSupported(__METHOD__);
2822
    }
2823
2824
    /**
2825
     * Returns the SQL to list all views of a database or user.
2826
     *
2827
     * @param string $database
2828
     *
2829
     * @return string
2830
     *
2831
     * @throws DBALException If not supported on this platform.
2832
     */
2833
    public function getListViewsSQL($database)
2834
    {
2835
        throw DBALException::notSupported(__METHOD__);
2836
    }
2837
2838
    /**
2839
     * Returns the list of indexes for the current database.
2840
     *
2841
     * The current database parameter is optional but will always be passed
2842
     * when using the SchemaManager API and is the database the given table is in.
2843
     *
2844
     * Attention: Some platforms only support currentDatabase when they
2845
     * are connected with that database. Cross-database information schema
2846
     * requests may be impossible.
2847
     *
2848
     * @param string $table
2849
     * @param string $currentDatabase
2850
     *
2851
     * @return string
2852
     *
2853
     * @throws DBALException If not supported on this platform.
2854
     */
2855
    public function getListTableIndexesSQL($table, $currentDatabase = null)
2856
    {
2857
        throw DBALException::notSupported(__METHOD__);
2858
    }
2859
2860
    /**
2861
     * @param string $table
2862
     *
2863
     * @return string
2864
     *
2865
     * @throws DBALException If not supported on this platform.
2866
     */
2867
    public function getListTableForeignKeysSQL($table)
2868
    {
2869
        throw DBALException::notSupported(__METHOD__);
2870
    }
2871
2872
    /**
2873
     * @param string $name
2874
     * @param string $sql
2875
     *
2876
     * @return string
2877
     *
2878
     * @throws DBALException If not supported on this platform.
2879
     */
2880
    public function getCreateViewSQL($name, $sql)
2881
    {
2882
        throw DBALException::notSupported(__METHOD__);
2883
    }
2884
2885
    /**
2886
     * @param string $name
2887
     *
2888
     * @return string
2889
     *
2890
     * @throws DBALException If not supported on this platform.
2891
     */
2892
    public function getDropViewSQL($name)
2893
    {
2894
        throw DBALException::notSupported(__METHOD__);
2895
    }
2896
2897
    /**
2898
     * Returns the SQL snippet to drop an existing sequence.
2899
     *
2900
     * @param Sequence|string $sequence
2901
     *
2902
     * @return string
2903
     *
2904
     * @throws DBALException If not supported on this platform.
2905
     */
2906
    public function getDropSequenceSQL($sequence)
0 ignored issues
show
Unused Code introduced by
The parameter $sequence is not used and could be removed. ( Ignorable by Annotation )

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

2906
    public function getDropSequenceSQL(/** @scrutinizer ignore-unused */ $sequence)

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

Loading history...
2907
    {
2908
        throw DBALException::notSupported(__METHOD__);
2909
    }
2910
2911
    /**
2912
     * @param string $sequenceName
2913
     *
2914
     * @return string
2915
     *
2916
     * @throws DBALException If not supported on this platform.
2917
     */
2918
    public function getSequenceNextValSQL($sequenceName)
0 ignored issues
show
Unused Code introduced by
The parameter $sequenceName is not used and could be removed. ( Ignorable by Annotation )

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

2918
    public function getSequenceNextValSQL(/** @scrutinizer ignore-unused */ $sequenceName)

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

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

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

3483
    public function getTruncateTableSQL($tableName, /** @scrutinizer ignore-unused */ $cascade = false)

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

Loading history...
3484
    {
3485 58754
        $tableIdentifier = new Identifier($tableName);
3486
3487 58754
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3488
    }
3489
3490
    /**
3491
     * This is for test reasons, many vendors have special requirements for dummy statements.
3492
     *
3493
     * @return string
3494
     */
3495 63460
    public function getDummySelectSQL()
3496
    {
3497 63460
        $expression = func_num_args() > 0 ? func_get_arg(0) : '1';
3498
3499 63460
        return sprintf('SELECT %s', $expression);
3500
    }
3501
3502
    /**
3503
     * Returns the SQL to create a new savepoint.
3504
     *
3505
     * @param string $savepoint
3506
     *
3507
     * @return string
3508
     */
3509 56033
    public function createSavePoint($savepoint)
3510
    {
3511 56033
        return 'SAVEPOINT ' . $savepoint;
3512
    }
3513
3514
    /**
3515
     * Returns the SQL to release a savepoint.
3516
     *
3517
     * @param string $savepoint
3518
     *
3519
     * @return string
3520
     */
3521 56031
    public function releaseSavePoint($savepoint)
3522
    {
3523 56031
        return 'RELEASE SAVEPOINT ' . $savepoint;
3524
    }
3525
3526
    /**
3527
     * Returns the SQL to rollback a savepoint.
3528
     *
3529
     * @param string $savepoint
3530
     *
3531
     * @return string
3532
     */
3533 56033
    public function rollbackSavePoint($savepoint)
3534
    {
3535 56033
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3536
    }
3537
3538
    /**
3539
     * Returns the keyword list instance of this platform.
3540
     *
3541
     * @return KeywordList
3542
     *
3543
     * @throws DBALException If no keyword list is specified.
3544
     */
3545 65944
    final public function getReservedKeywordsList()
3546
    {
3547
        // Check for an existing instantiation of the keywords class.
3548 65944
        if ($this->_keywords) {
3549 65810
            return $this->_keywords;
3550
        }
3551
3552 65625
        $class    = $this->getReservedKeywordsClass();
3553 65625
        $keywords = new $class();
3554 65625
        if (! $keywords instanceof KeywordList) {
3555
            throw DBALException::notSupported(__METHOD__);
3556
        }
3557
3558
        // Store the instance so it doesn't need to be generated on every request.
3559 65625
        $this->_keywords = $keywords;
3560
3561 65625
        return $keywords;
3562
    }
3563
3564
    /**
3565
     * Returns the class name of the reserved keywords list.
3566
     *
3567
     * @return string
3568
     *
3569
     * @throws DBALException If not supported on this platform.
3570
     */
3571
    protected function getReservedKeywordsClass()
3572
    {
3573
        throw DBALException::notSupported(__METHOD__);
3574
    }
3575
3576
    /**
3577
     * Quotes a literal string.
3578
     * This method is NOT meant to fix SQL injections!
3579
     * It is only meant to escape this platform's string literal
3580
     * quote character inside the given literal string.
3581
     *
3582
     * @param string $str The literal string to be quoted.
3583
     *
3584
     * @return string The quoted literal string.
3585
     */
3586 62832
    public function quoteStringLiteral($str)
3587
    {
3588 62832
        $c = $this->getStringLiteralQuoteCharacter();
3589
3590 62832
        return $c . str_replace($c, $c . $c, $str) . $c;
3591
    }
3592
3593
    /**
3594
     * Gets the character used for string literal quoting.
3595
     *
3596
     * @return string
3597
     */
3598 62868
    public function getStringLiteralQuoteCharacter()
3599
    {
3600 62868
        return "'";
3601
    }
3602
3603
    /**
3604
     * Escapes metacharacters in a string intended to be used with a LIKE
3605
     * operator.
3606
     *
3607
     * @param string $inputString a literal, unquoted string
3608
     * @param string $escapeChar  should be reused by the caller in the LIKE
3609
     *                            expression.
3610
     */
3611 62475
    final public function escapeStringForLike(string $inputString, string $escapeChar) : string
3612
    {
3613 62475
        return preg_replace(
3614 62475
            '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u',
3615 62475
            addcslashes($escapeChar, '\\') . '$1',
3616 62475
            $inputString
3617
        );
3618
    }
3619
3620 62475
    protected function getLikeWildcardCharacters() : string
3621
    {
3622 62475
        return '%_';
3623
    }
3624
}
3625