Failed Conditions
Push — drop-deprecated ( d77510...d983c4 )
by Michael
40:59 queued 38:23
created

AbstractPlatform   F

Complexity

Total Complexity 391

Size/Duplication

Total Lines 3388
Duplicated Lines 0 %

Test Coverage

Coverage 79.74%

Importance

Changes 0
Metric Value
wmc 391
eloc 648
dl 0
loc 3388
ccs 669
cts 839
cp 0.7974
rs 1.952
c 0
b 0
f 0

209 Methods

Rating   Name   Duplication   Size   Complexity  
A supportsAlterTable() 0 3 1
A getEventManager() 0 3 1
A getSequencePrefix() 0 10 4
A supportsForeignKeyOnUpdate() 0 3 1
A getCheckDeclarationSQL() 0 18 5
A getWriteLockSQL() 0 3 1
A getCharMaxLength() 0 3 1
A getCreateSchemaSQL() 0 3 1
A getLtrimExpression() 0 3 1
A getFloatDeclarationSQL() 0 3 1
A getDefaultSchemaName() 0 3 1
A supportsCreateDropDatabase() 0 3 1
A onSchemaAlterTableRenameColumn() 0 16 3
A getCreateDatabaseSQL() 0 3 1
A getListTableColumnsSQL() 0 3 1
A initializeCommentedDoctrineTypes() 0 12 3
A supportsLimitOffset() 0 3 1
A supportsSavepoints() 0 3 1
A getDateTimeTzTypeDeclarationSQL() 0 3 1
A getCosExpression() 0 3 1
F getCreateTableSQL() 0 97 24
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 getDateTimeTypeDeclarationSQL() 0 3 1
A supportsCommentOnStatement() 0 3 1
A convertFromBoolean() 0 3 2
A getSqrtExpression() 0 3 1
A getDateSubMonthExpression() 0 3 1
A _getAlterTableIndexForeignKeySQL() 0 3 1
A getTemporaryTableSQL() 0 3 1
A getDateAddYearsExpression() 0 3 1
A getCreateIndexSQL() 0 20 4
A getDropSequenceSQL() 0 3 1
A getDefaultTransactionIsolationLevel() 0 3 1
A getBetweenExpression() 0 3 1
A getMaxIdentifierLength() 0 3 1
A getIsNullExpression() 0 3 1
A getSqlCommentStartString() 0 3 1
A getUpperExpression() 0 3 1
A _getTransactionIsolationLevelSQL() 0 13 5
A getForeignKeyDeclarationSQL() 0 6 1
A prefersIdentityColumns() 0 3 1
A getDropForeignKeySQL() 0 14 3
A getBinaryDefaultLength() 0 3 1
A getListNamespacesSQL() 0 3 1
A getSumExpression() 0 3 1
A registerDoctrineTypeMapping() 0 20 4
A appendLockHint() 0 3 1
A markDoctrineTypeCommented() 0 9 3
A getSqlCommentEndString() 0 3 1
A getUniqueConstraintDeclarationSQL() 0 20 4
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 getCreateViewSQL() 0 3 1
A getColumnCharsetDeclarationSQL() 0 3 1
A getGuidTypeDeclarationSQL() 0 6 1
A getDateFormatString() 0 3 1
A getListUsersSQL() 0 3 1
A getPiExpression() 0 3 1
A getListSequencesSQL() 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 convertBooleansToDatabaseValue() 0 3 1
A supportsIdentityColumns() 0 3 1
A getIdentitySequenceName() 0 3 1
A getBinaryMaxLength() 0 3 1
A getReadLockSQL() 0 3 1
A getAcosExpression() 0 3 1
A getSequenceNextValSQL() 0 3 1
A getDoctrineTypeComment() 0 3 1
A getMd5Expression() 0 3 1
A getCurrentDateSQL() 0 3 1
A getCustomTypeDeclarationSQL() 0 3 1
A supportsPartialIndexes() 0 3 1
A getCountExpression() 0 3 1
A prefersSequences() 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
A getColumnCollationDeclarationSQL() 0 3 2
F getColumnDeclarationSQL() 0 30 15
A getDropConstraintSQL() 0 14 3
A getCommentOnColumnSQL() 0 10 1
A getDateSubQuartersExpression() 0 3 1
C getDefaultValueDeclarationSQL() 0 35 12
A supportsSchemas() 0 3 1
A getSQLResultCasing() 0 3 1
A getDropViewSQL() 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 quoteSingleIdentifier() 0 5 1
A supportsSequences() 0 3 1
A getCurrentTimeSQL() 0 3 1
A getDateAddWeeksExpression() 0 3 1
A supportsReleaseSavepoints() 0 3 1
A getDummySelectSQL() 0 3 1
A getDropIndexSQL() 0 9 3
A supportsIndexes() 0 3 1
A getIndexFieldDeclarationListSQL() 0 21 5
A hasDoctrineTypeMappingFor() 0 9 2
A getDateSubMinutesExpression() 0 3 1
A getDateSubHourExpression() 0 3 1
A getDateTypeDeclarationSQL() 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 multiplyInterval() 0 3 1
A getTruncateTableSQL() 0 5 1
A getDateSubWeeksExpression() 0 3 1
A getLikeWildcardCharacters() 0 3 1
A usesSequenceEmulatedIdentityColumns() 0 3 1
A getSetTransactionIsolationSQL() 0 3 1
A getDateAddDaysExpression() 0 3 1
A getIdentifierQuoteCharacter() 0 3 1
A getDateSubDaysExpression() 0 3 1
A getListTableForeignKeysSQL() 0 3 1
A __construct() 0 2 1
B getPostAlterTableIndexForeignKeySQL() 0 38 8
C _getCreateTableSQL() 0 37 12
A onSchemaAlterTable() 0 16 3
A getListViewsSQL() 0 3 1
A getUniqueFieldDeclarationSQL() 0 3 1
A initializeAllDoctrineTypeMappings() 0 7 3
A isCommentedDoctrineType() 0 9 2
A getRegexpExpression() 0 3 1
A getDoctrineTypeMapping() 0 13 3
A supportsForeignKeyConstraints() 0 3 1
A modifyLimitQuery() 0 17 4
A getTimeFormatString() 0 3 1
A getBitOrComparisonExpression() 0 3 1
A getTimeTypeDeclarationSQL() 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 getCreateSequenceSQL() 0 3 1
A getVarcharTypeDeclarationSQL() 0 17 4
A getDateSubSecondsExpression() 0 3 1
A getDateTimeTzFormatString() 0 3 1
A setEventManager() 0 3 1
A supportsGettingAffectedRows() 0 3 1
A getRoundExpression() 0 3 1
A getCurrentTimestampSQL() 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 getListTableConstraintsSQL() 0 3 1
A getAlterSequenceSQL() 0 3 1
A getDateArithmeticIntervalExpression() 0 3 1
A getDateAddMinutesExpression() 0 3 1
A getBinaryTypeDeclarationSQL() 0 9 2
A getIndexDeclarationSQL() 0 12 2
A getJsonTypeDeclarationSQL() 0 3 1
A getListTableIndexesSQL() 0 3 1
A getConcatExpression() 0 3 1
A getLocateExpression() 0 3 1
A getWildcards() 0 3 1
A getListTablesSQL() 0 3 1
A getEmptyIdentityInsertSQL() 0 3 1
A supportsInlineColumnComments() 0 3 1
A quoteIdentifier() 0 9 2
B getTrimExpression() 0 40 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
A getForeignKeyReferentialActionSQL() 0 12 6
A getListDatabasesSQL() 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
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Platforms;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\DBAL\DBALException;
9
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
10
use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
11
use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
12
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
13
use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
14
use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
15
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
16
use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
17
use Doctrine\DBAL\Events;
18
use Doctrine\DBAL\Platforms\Keywords\KeywordList;
19
use Doctrine\DBAL\Schema\Column;
20
use Doctrine\DBAL\Schema\ColumnDiff;
21
use Doctrine\DBAL\Schema\Constraint;
22
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
23
use Doctrine\DBAL\Schema\Identifier;
24
use Doctrine\DBAL\Schema\Index;
25
use Doctrine\DBAL\Schema\Sequence;
26
use Doctrine\DBAL\Schema\Table;
27
use Doctrine\DBAL\Schema\TableDiff;
28
use Doctrine\DBAL\Schema\UniqueConstraint;
29
use Doctrine\DBAL\TransactionIsolationLevel;
30
use Doctrine\DBAL\Types;
31
use Doctrine\DBAL\Types\Type;
32
use InvalidArgumentException;
33
use UnexpectedValueException;
34
use function addcslashes;
35
use function array_map;
36
use function array_merge;
37
use function array_unique;
38
use function array_values;
39
use function assert;
40
use function count;
41
use function explode;
42
use function implode;
43
use function in_array;
44
use function is_array;
45
use function is_bool;
46
use function is_int;
47
use function is_string;
48
use function preg_quote;
49
use function preg_replace;
50
use function sprintf;
51
use function str_replace;
52
use function strlen;
53
use function strpos;
54
use function strtolower;
55
use function strtoupper;
56
57
/**
58
 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
59
 * point of abstraction of platform-specific behaviors, features and SQL dialects.
60
 * They are a passive source of information.
61
 *
62
 * @todo Remove any unnecessary methods.
63
 */
64
abstract class AbstractPlatform
65
{
66
    public const CREATE_INDEXES = 1;
67
68
    public const CREATE_FOREIGNKEYS = 2;
69
70
    /** @var string[]|null */
71
    protected $doctrineTypeMapping = null;
72
73
    /**
74
     * Contains a list of all columns that should generate parseable column comments for type-detection
75
     * in reverse engineering scenarios.
76
     *
77
     * @var string[]|null
78
     */
79
    protected $doctrineTypeComments = null;
80
81
    /** @var EventManager */
82
    protected $_eventManager;
83
84
    /**
85
     * Holds the KeywordList instance for the current platform.
86
     *
87
     * @var KeywordList|null
88
     */
89
    protected $_keywords;
90
91 49880
    public function __construct()
92
    {
93 49880
    }
94
95
    /**
96
     * Sets the EventManager used by the Platform.
97
     */
98 49788
    public function setEventManager(EventManager $eventManager)
99
    {
100 49788
        $this->_eventManager = $eventManager;
101 49788
    }
102
103
    /**
104
     * Gets the EventManager used by the Platform.
105
     *
106
     * @return EventManager
107
     */
108 46426
    public function getEventManager()
109
    {
110 46426
        return $this->_eventManager;
111
    }
112
113
    /**
114
     * Returns the SQL snippet that declares a boolean column.
115
     *
116
     * @param mixed[] $columnDef
117
     *
118
     * @return string
119
     */
120
    abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
121
122
    /**
123
     * Returns the SQL snippet that declares a 4 byte integer column.
124
     *
125
     * @param mixed[] $columnDef
126
     *
127
     * @return string
128
     */
129
    abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
130
131
    /**
132
     * Returns the SQL snippet that declares an 8 byte integer column.
133
     *
134
     * @param mixed[] $columnDef
135
     *
136
     * @return string
137
     */
138
    abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
139
140
    /**
141
     * Returns the SQL snippet that declares a 2 byte integer column.
142
     *
143
     * @param mixed[] $columnDef
144
     *
145
     * @return string
146
     */
147
    abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
148
149
    /**
150
     * Returns the SQL snippet that declares common properties of an integer column.
151
     *
152
     * @param mixed[] $columnDef
153
     *
154
     * @return string
155
     */
156
    abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
157
158
    /**
159
     * Lazy load Doctrine Type Mappings.
160
     *
161
     * @return void
162
     */
163
    abstract protected function initializeDoctrineTypeMappings();
164
165
    /**
166
     * Initializes Doctrine Type Mappings with the platform defaults
167
     * and with all additional type mappings.
168
     *
169
     * @return void
170
     */
171 46426
    private function initializeAllDoctrineTypeMappings()
172
    {
173 46426
        $this->initializeDoctrineTypeMappings();
174
175 46426
        foreach (Type::getTypesMap() as $typeName => $className) {
176 46426
            foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
177 28075
                $this->doctrineTypeMapping[$dbType] = $typeName;
178
            }
179
        }
180 46426
    }
181
182
    /**
183
     * Returns the SQL snippet used to declare a VARCHAR column type.
184
     *
185
     * @param mixed[] $field
186
     *
187
     * @return string
188
     */
189 48817
    public function getVarcharTypeDeclarationSQL(array $field)
190
    {
191 48817
        if (! isset($field['length'])) {
192 45109
            $field['length'] = $this->getVarcharDefaultLength();
193
        }
194
195 48817
        $fixed = $field['fixed'] ?? false;
196
197 48817
        $maxLength = $fixed
198 46541
            ? $this->getCharMaxLength()
199 48817
            : $this->getVarcharMaxLength();
200
201 48817
        if ($field['length'] > $maxLength) {
202
            return $this->getClobTypeDeclarationSQL($field);
203
        }
204
205 48817
        return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed);
206
    }
207
208
    /**
209
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
210
     *
211
     * @param mixed[] $field The column definition.
212
     *
213
     * @return string
214
     */
215 45230
    public function getBinaryTypeDeclarationSQL(array $field)
216
    {
217 45230
        if (! isset($field['length'])) {
218 45198
            $field['length'] = $this->getBinaryDefaultLength();
219
        }
220
221 45230
        $fixed = $field['fixed'] ?? false;
222
223 45230
        return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed);
224
    }
225
226
    /**
227
     * Returns the SQL snippet to declare a GUID/UUID field.
228
     *
229
     * By default this maps directly to a CHAR(36) and only maps to more
230
     * special datatypes when the underlying databases support this datatype.
231
     *
232
     * @param mixed[] $field
233
     *
234
     * @return string
235
     */
236 44723
    public function getGuidTypeDeclarationSQL(array $field)
237
    {
238 44723
        $field['length'] = 36;
239 44723
        $field['fixed']  = true;
240
241 44723
        return $this->getVarcharTypeDeclarationSQL($field);
242
    }
243
244
    /**
245
     * Returns the SQL snippet to declare a JSON field.
246
     *
247
     * By default this maps directly to a CLOB and only maps to more
248
     * special datatypes when the underlying databases support this datatype.
249
     *
250
     * @param mixed[] $field
251
     *
252
     * @return string
253
     */
254 42765
    public function getJsonTypeDeclarationSQL(array $field)
255
    {
256 42765
        return $this->getClobTypeDeclarationSQL($field);
257
    }
258
259
    /**
260
     * @param int  $length
261
     * @param bool $fixed
262
     *
263
     * @return string
264
     *
265
     * @throws DBALException If not supported on this platform.
266
     */
267
    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

267
    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...
268
    {
269
        throw DBALException::notSupported('VARCHARs not supported by Platform.');
270
    }
271
272
    /**
273
     * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
274
     *
275
     * @param int  $length The length of the column.
276
     * @param bool $fixed  Whether the column length is fixed.
277
     *
278
     * @return string
279
     *
280
     * @throws DBALException If not supported on this platform.
281
     */
282
    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

282
    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...
283
    {
284
        throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.');
285
    }
286
287
    /**
288
     * Returns the SQL snippet used to declare a CLOB column type.
289
     *
290
     * @param mixed[] $field
291
     *
292
     * @return string
293
     */
294
    abstract public function getClobTypeDeclarationSQL(array $field);
295
296
    /**
297
     * Returns the SQL Snippet used to declare a BLOB column type.
298
     *
299
     * @param mixed[] $field
300
     *
301
     * @return string
302
     */
303
    abstract public function getBlobTypeDeclarationSQL(array $field);
304
305
    /**
306
     * Gets the name of the platform.
307
     *
308
     * @return string
309
     */
310
    abstract public function getName();
311
312
    /**
313
     * Registers a doctrine type to be used in conjunction with a column type of this platform.
314
     *
315
     * @param string $dbType
316
     * @param string $doctrineType
317
     *
318
     * @throws DBALException If the type is not found.
319
     */
320 44649
    public function registerDoctrineTypeMapping($dbType, $doctrineType)
321
    {
322 44649
        if ($this->doctrineTypeMapping === null) {
323 44088
            $this->initializeAllDoctrineTypeMappings();
324
        }
325
326 44649
        if (! Types\Type::hasType($doctrineType)) {
327 42435
            throw DBALException::typeNotFound($doctrineType);
328
        }
329
330 44649
        $dbType                             = strtolower($dbType);
331 44649
        $this->doctrineTypeMapping[$dbType] = $doctrineType;
332
333 44649
        $doctrineType = Type::getType($doctrineType);
334
335 44649
        if (! $doctrineType->requiresSQLCommentHint($this)) {
336 44649
            return;
337
        }
338
339 42412
        $this->markDoctrineTypeCommented($doctrineType);
340 42412
    }
341
342
    /**
343
     * Gets the Doctrine type that is mapped for the given database column type.
344
     *
345
     * @param string $dbType
346
     *
347
     * @return string
348
     *
349
     * @throws DBALException
350
     */
351 46426
    public function getDoctrineTypeMapping($dbType)
352
    {
353 46426
        if ($this->doctrineTypeMapping === null) {
354 46426
            $this->initializeAllDoctrineTypeMappings();
355
        }
356
357 46426
        $dbType = strtolower($dbType);
358
359 46426
        if (! isset($this->doctrineTypeMapping[$dbType])) {
360 42481
            throw new DBALException('Unknown database type ' . $dbType . ' requested, ' . static::class . ' may not support it.');
361
        }
362
363 46426
        return $this->doctrineTypeMapping[$dbType];
364
    }
365
366
    /**
367
     * Checks if a database type is currently supported by this platform.
368
     *
369
     * @param string $dbType
370
     *
371
     * @return bool
372
     */
373 43992
    public function hasDoctrineTypeMappingFor($dbType)
374
    {
375 43992
        if ($this->doctrineTypeMapping === null) {
376 40526
            $this->initializeAllDoctrineTypeMappings();
377
        }
378
379 43992
        $dbType = strtolower($dbType);
380
381 43992
        return isset($this->doctrineTypeMapping[$dbType]);
382
    }
383
384
    /**
385
     * Initializes the Doctrine Type comments instance variable for in_array() checks.
386
     *
387
     * @return void
388
     */
389 49107
    protected function initializeCommentedDoctrineTypes()
390
    {
391 49107
        $this->doctrineTypeComments = [];
392
393 49107
        foreach (Type::getTypesMap() as $typeName => $className) {
394 49107
            $type = Type::getType($typeName);
395
396 49107
            if (! $type->requiresSQLCommentHint($this)) {
397 49107
                continue;
398
            }
399
400 49107
            $this->doctrineTypeComments[] = $typeName;
401
        }
402 49107
    }
403
404
    /**
405
     * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type?
406
     *
407
     * @return bool
408
     */
409 49107
    public function isCommentedDoctrineType(Type $doctrineType)
410
    {
411 49107
        if ($this->doctrineTypeComments === null) {
412 49107
            $this->initializeCommentedDoctrineTypes();
413
        }
414
415 49107
        assert(is_array($this->doctrineTypeComments));
416
417 49107
        return in_array($doctrineType->getName(), $this->doctrineTypeComments);
418
    }
419
420
    /**
421
     * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements.
422
     *
423
     * @param string|Type $doctrineType
424
     *
425
     * @return void
426
     */
427 42412
    public function markDoctrineTypeCommented($doctrineType)
428
    {
429 42412
        if ($this->doctrineTypeComments === null) {
430 42412
            $this->initializeCommentedDoctrineTypes();
431
        }
432
433 42412
        assert(is_array($this->doctrineTypeComments));
434
435 42412
        $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
436 42412
    }
437
438
    /**
439
     * Gets the comment to append to a column comment that helps parsing this type in reverse engineering.
440
     *
441
     * @return string
442
     */
443 45672
    public function getDoctrineTypeComment(Type $doctrineType)
444
    {
445 45672
        return '(DC2Type:' . $doctrineType->getName() . ')';
446
    }
447
448
    /**
449
     * Gets the comment of a passed column modified by potential doctrine type comment hints.
450
     *
451
     * @return string|null
452
     */
453 49107
    protected function getColumnComment(Column $column)
454
    {
455 49107
        $comment = $column->getComment();
456
457 49107
        if ($this->isCommentedDoctrineType($column->getType())) {
458 45672
            $comment .= $this->getDoctrineTypeComment($column->getType());
459
        }
460
461 49107
        return $comment;
462
    }
463
464
    /**
465
     * Gets the character used for identifier quoting.
466
     *
467
     * @return string
468
     */
469 44513
    public function getIdentifierQuoteCharacter()
470
    {
471 44513
        return '"';
472
    }
473
474
    /**
475
     * Gets the string portion that starts an SQL comment.
476
     *
477
     * @return string
478
     */
479
    public function getSqlCommentStartString()
480
    {
481
        return '--';
482
    }
483
484
    /**
485
     * Gets the string portion that ends an SQL comment.
486
     *
487
     * @return string
488
     */
489
    public function getSqlCommentEndString()
490
    {
491
        return "\n";
492
    }
493
494
    /**
495
     * Gets the maximum length of a char field.
496
     */
497 46299
    public function getCharMaxLength() : int
498
    {
499 46299
        return $this->getVarcharMaxLength();
500
    }
501
502
    /**
503
     * Gets the maximum length of a varchar field.
504
     *
505
     * @return int
506
     */
507 43846
    public function getVarcharMaxLength()
508
    {
509 43846
        return 4000;
510
    }
511
512
    /**
513
     * Gets the default length of a varchar field.
514
     *
515
     * @return int
516
     */
517 45109
    public function getVarcharDefaultLength()
518
    {
519 45109
        return 255;
520
    }
521
522
    /**
523
     * Gets the maximum length of a binary field.
524
     *
525
     * @return int
526
     */
527
    public function getBinaryMaxLength()
528
    {
529
        return 4000;
530
    }
531
532
    /**
533
     * Gets the default length of a binary field.
534
     *
535
     * @return int
536
     */
537 43475
    public function getBinaryDefaultLength()
538
    {
539 43475
        return 255;
540
    }
541
542
    /**
543
     * Gets all SQL wildcard characters of the platform.
544
     *
545
     * @return string[]
546
     */
547
    public function getWildcards()
548
    {
549
        return ['%', '_'];
550
    }
551
552
    /**
553
     * Returns the regular expression operator.
554
     *
555
     * @throws DBALException If not supported on this platform.
556
     */
557 30958
    public function getRegexpExpression() : string
558
    {
559 30958
        throw DBALException::notSupported(__METHOD__);
560
    }
561
562
    /**
563
     * Returns the SQL snippet to get the average value of a column.
564
     *
565
     * @param string $value SQL expression producing the value.
566
     */
567
    public function getAvgExpression(string $value) : string
568
    {
569
        return 'AVG(' . $value . ')';
570
    }
571
572
    /**
573
     * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
574
     *
575
     * If a '*' is used instead of a column the number of selected rows is returned.
576
     *
577
     * @param string $expression The expression to count.
578
     */
579
    public function getCountExpression(string $expression) : string
580
    {
581
        return 'COUNT(' . $expression . ')';
582
    }
583
584
    /**
585
     * Returns the SQL snippet to get the maximum value in a set of values.
586
     *
587
     * @param string $value SQL expression producing the value.
588
     */
589
    public function getMaxExpression(string $value) : string
590
    {
591
        return 'MAX(' . $value . ')';
592
    }
593
594
    /**
595
     * Returns the SQL snippet to get the minimum value in a set of values.
596
     *
597
     * @param string $value SQL expression producing the value.
598
     */
599
    public function getMinExpression(string $value) : string
600
    {
601
        return 'MIN(' . $value . ')';
602
    }
603
604
    /**
605
     * Returns the SQL snippet to get the total sum of the values in a set.
606
     *
607
     * @param string $value SQL expression producing the value.
608
     */
609
    public function getSumExpression(string $value) : string
610
    {
611
        return 'SUM(' . $value . ')';
612
    }
613
614
    // scalar functions
615
616
    /**
617
     * Returns the SQL snippet to get the md5 sum of the value.
618
     *
619
     * Note: Not SQL92, but common functionality.
620
     *
621
     * @param string $string SQL expression producing the string.
622
     */
623
    public function getMd5Expression(string $string) : string
624
    {
625
        return 'MD5(' . $string . ')';
626
    }
627
628
    /**
629
     * Returns the SQL snippet to get the length of a text field.
630
     *
631
     * @param string $string SQL expression producing the string.
632
     */
633
    public function getLengthExpression(string $string) : string
634
    {
635
        return 'LENGTH(' . $string . ')';
636
    }
637
638
    /**
639
     * Returns the SQL snippet to get the square root of the value.
640
     *
641
     * @param string $number SQL expression producing the number.
642
     */
643
    public function getSqrtExpression(string $number) : string
644
    {
645
        return 'SQRT(' . $number . ')';
646
    }
647
648
    /**
649
     * Returns the SQL snippet to round a number to the number of decimals specified.
650
     *
651
     * @param string $number   SQL expression producing the number to round.
652
     * @param string $decimals SQL expression producing the number of decimals.
653
     */
654
    public function getRoundExpression(string $number, string $decimals = '0') : string
655
    {
656
        return 'ROUND(' . $number . ', ' . $decimals . ')';
657
    }
658
659
    /**
660
     * Returns the SQL snippet to get the remainder of the operation of division of dividend by divisor.
661
     *
662
     * @param string $dividend SQL expression producing the dividend.
663
     * @param string $divisor  SQL expression producing the divisor.
664
     */
665
    public function getModExpression(string $dividend, string $divisor) : string
666
    {
667
        return 'MOD(' . $dividend . ', ' . $divisor . ')';
668
    }
669
670
    /**
671
     * Returns the SQL snippet to trim a string.
672
     *
673
     * @param string      $str  The expression to apply the trim to.
674
     * @param int         $mode The position of the trim (leading/trailing/both).
675
     * @param string|null $char The char to trim, has to be quoted already. Defaults to space.
676
     *
677
     * @throws InvalidArgumentException
678
     */
679 44498
    public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string
680
    {
681 44498
        $tokens = [];
682
683 44498
        switch ($mode) {
684
            case TrimMode::UNSPECIFIED:
685 44498
                break;
686
687
            case TrimMode::LEADING:
688 44477
                $tokens[] = 'LEADING';
689 44477
                break;
690
691
            case TrimMode::TRAILING:
692 44456
                $tokens[] = 'TRAILING';
693 44456
                break;
694
695
            case TrimMode::BOTH:
696 44456
                $tokens[] = 'BOTH';
697 44456
                break;
698
699
            default:
700 43973
                throw new InvalidArgumentException(
701 43973
                    sprintf(
702
                        'The value of $mode is expected to be one of the TrimMode constants, %d given',
703 43973
                        $mode
704
                    )
705
                );
706
        }
707
708 44498
        if ($char !== null) {
709 44435
            $tokens[] = $char;
710
        }
711
712 44498
        if (count($tokens) > 0) {
713 44477
            $tokens[] = 'FROM';
714
        }
715
716 44498
        $tokens[] = $str;
717
718 44498
        return sprintf('TRIM(%s)', implode(' ', $tokens));
719
    }
720
721
    /**
722
     * Returns the SQL snippet to trim trailing space characters from the string.
723
     *
724
     * @param string $string SQL expression producing the string.
725
     */
726 15571
    public function getRtrimExpression(string $string) : string
727
    {
728 15571
        return 'RTRIM(' . $string . ')';
729
    }
730
731
    /**
732
     * Returns the SQL snippet to trim leading space characters from the string.
733
     *
734
     * @param string $string SQL expression producing the string.
735
     */
736 15571
    public function getLtrimExpression(string $string) : string
737
    {
738 15571
        return 'LTRIM(' . $string . ')';
739
    }
740
741
    /**
742
     * Returns the SQL snippet to change all characters from the string to uppercase,
743
     * according to the current character set mapping.
744
     *
745
     * @param string $string SQL expression producing the string.
746
     */
747
    public function getUpperExpression(string $string) : string
748
    {
749
        return 'UPPER(' . $string . ')';
750
    }
751
752
    /**
753
     * Returns the SQL snippet to change all characters from the string to lowercase,
754
     * according to the current character set mapping.
755
     *
756
     * @param string $string SQL expression producing the string.
757
     */
758
    public function getLowerExpression(string $string) : string
759
    {
760
        return 'LOWER(' . $string . ')';
761
    }
762
763
    /**
764
     * Returns the SQL snippet to get the position of the first occurrence of the substring in the string.
765
     *
766
     * @param string      $string    SQL expression producing the string to locate the substring in.
767
     * @param string      $substring SQL expression producing the substring to locate.
768
     * @param string|null $start     SQL expression producing the position to start at.
769
     *                               Defaults to the beginning of the string.
770
     *
771
     * @throws DBALException If not supported on this platform.
772
     */
773
    public function getLocateExpression(string $string, string $substring, ?string $start = null) : string
0 ignored issues
show
Unused Code introduced by
The parameter $substring 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

773
    public function getLocateExpression(string $string, /** @scrutinizer ignore-unused */ string $substring, ?string $start = null) : string

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...
774
    {
775
        throw DBALException::notSupported(__METHOD__);
776
    }
777
778
    /**
779
     * Returns the SQL snippet to get the current system date.
780
     */
781
    public function getNowExpression() : string
782
    {
783
        return 'NOW()';
784
    }
785
786
    /**
787
     * Returns an SQL snippet to get a substring inside the string.
788
     *
789
     * Note: Not SQL92, but common functionality.
790
     *
791
     * @param string      $string SQL expression producing the string from which a substring should be extracted.
792
     * @param string      $start  SQL expression producing the position to start at,
793
     * @param string|null $length SQL expression producing the length of the substring portion to be returned.
794
     *                            By default, the entire substring is returned.
795
     */
796 44895
    public function getSubstringExpression(string $string, string $start, ?string $length = null) : string
797
    {
798 44895
        if ($length === null) {
799 44895
            return sprintf('SUBSTRING(%s FROM %s)', $string, $start);
800
        }
801
802 44869
        return sprintf('SUBSTRING(%s FROM %s FOR %s)', $string, $start, $length);
803
    }
804
805
    /**
806
     * Returns a SQL snippet to concatenate the given strings.
807
     *
808
     * @param string[] ...$string
809
     */
810 30935
    public function getConcatExpression(string ...$string) : string
811
    {
812 30935
        return implode(' || ', $string);
813
    }
814
815
    /**
816
     * Returns the SQL for a logical not.
817
     *
818
     * @param string $value SQL expression producing the value to negate.
819
     */
820
    public function getNotExpression(string $value) : string
821
    {
822
        return 'NOT(' . $value . ')';
823
    }
824
825
    /**
826
     * Returns the SQL that checks if an expression is null.
827
     *
828
     * @param string $value SQL expression producing the to be compared to null.
829
     */
830 49834
    public function getIsNullExpression(string $value) : string
831
    {
832 49834
        return $value . ' IS NULL';
833
    }
834
835
    /**
836
     * Returns the SQL that checks if an expression is not null.
837
     *
838
     * @param string $value SQL expression producing the to be compared to null.
839
     */
840
    public function getIsNotNullExpression(string $value) : string
841
    {
842
        return $value . ' IS NOT NULL';
843
    }
844
845
    /**
846
     * Returns the SQL that checks if an expression evaluates to a value between two values.
847
     *
848
     * The parameter $value is checked if it is between $min and $max.
849
     *
850
     * Note: There is a slight difference in the way BETWEEN works on some databases.
851
     * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
852
     * independence you should avoid using between().
853
     *
854
     * @param string $value SQL expression producing the value to compare.
855
     * @param string $min   SQL expression producing the lower value to compare with.
856
     * @param string $max   SQL expression producing the higher value to compare with.
857
     */
858
    public function getBetweenExpression(string $value, string $min, string $max) : string
859
    {
860
        return $value . ' BETWEEN ' . $min . ' AND ' . $max;
861
    }
862
863
    /**
864
     * Returns the SQL to get the arccosine of a value.
865
     *
866
     * @param string $number SQL expression producing the number.
867
     */
868
    public function getAcosExpression(string $number) : string
869
    {
870
        return 'ACOS(' . $number . ')';
871
    }
872
873
    /**
874
     * Returns the SQL to get the sine of a value.
875
     *
876
     * @param string $number SQL expression producing the number.
877
     */
878
    public function getSinExpression(string $number) : string
879
    {
880
        return 'SIN(' . $number . ')';
881
    }
882
883
    /**
884
     * Returns the SQL to get the PI value.
885
     */
886
    public function getPiExpression() : string
887
    {
888
        return 'PI()';
889
    }
890
891
    /**
892
     * Returns the SQL to get the cosine of a value.
893
     *
894
     * @param string $number SQL expression producing the number.
895
     */
896
    public function getCosExpression(string $number) : string
897
    {
898
        return 'COS(' . $number . ')';
899
    }
900
901
    /**
902
     * Returns the SQL to calculate the difference in days between the two passed dates.
903
     *
904
     * Computes diff = date1 - date2.
905
     *
906
     * @throws DBALException If not supported on this platform.
907
     */
908
    public function getDateDiffExpression(string $date1, string $date2) : string
0 ignored issues
show
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

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

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 $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

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

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...
909
    {
910
        throw DBALException::notSupported(__METHOD__);
911
    }
912
913
    /**
914
     * Returns the SQL to add the number of given seconds to a date.
915
     *
916
     * @param string $date    SQL expression producing the date.
917
     * @param string $seconds SQL expression producing the number of seconds.
918
     *
919
     * @throws DBALException If not supported on this platform.
920
     */
921 48078
    public function getDateAddSecondsExpression(string $date, string $seconds) : string
922
    {
923 48078
        return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND);
924
    }
925
926
    /**
927
     * Returns the SQL to subtract the number of given seconds from a date.
928
     *
929
     * @param string $date    SQL expression producing the date.
930
     * @param string $seconds SQL expression producing the number of seconds.
931
     *
932
     * @throws DBALException If not supported on this platform.
933
     */
934 48032
    public function getDateSubSecondsExpression(string $date, string $seconds) : string
935
    {
936 48032
        return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND);
937
    }
938
939
    /**
940
     * Returns the SQL to add the number of given minutes to a date.
941
     *
942
     * @param string $date    SQL expression producing the date.
943
     * @param string $minutes SQL expression producing the number of minutes.
944
     *
945
     * @throws DBALException If not supported on this platform.
946
     */
947 47986
    public function getDateAddMinutesExpression(string $date, string $minutes) : string
948
    {
949 47986
        return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE);
950
    }
951
952
    /**
953
     * Returns the SQL to subtract the number of given minutes from a date.
954
     *
955
     * @param string $date    SQL expression producing the date.
956
     * @param string $minutes SQL expression producing the number of minutes.
957
     *
958
     * @throws DBALException If not supported on this platform.
959
     */
960 47940
    public function getDateSubMinutesExpression(string $date, string $minutes) : string
961
    {
962 47940
        return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE);
963
    }
964
965
    /**
966
     * Returns the SQL to add the number of given hours to a date.
967
     *
968
     * @param string $date  SQL expression producing the date.
969
     * @param string $hours SQL expression producing the number of hours.
970
     *
971
     * @throws DBALException If not supported on this platform.
972
     */
973 47894
    public function getDateAddHourExpression(string $date, string $hours) : string
974
    {
975 47894
        return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR);
976
    }
977
978
    /**
979
     * Returns the SQL to subtract the number of given hours to a date.
980
     *
981
     * @param string $date  SQL expression producing the date.
982
     * @param string $hours SQL expression producing the number of hours.
983
     *
984
     * @throws DBALException If not supported on this platform.
985
     */
986 47848
    public function getDateSubHourExpression(string $date, string $hours) : string
987
    {
988 47848
        return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR);
989
    }
990
991
    /**
992
     * Returns the SQL to add the number of given days to a date.
993
     *
994
     * @param string $date SQL expression producing the date.
995
     * @param string $days SQL expression producing the number of days.
996
     *
997
     * @throws DBALException If not supported on this platform.
998
     */
999 47802
    public function getDateAddDaysExpression(string $date, string $days) : string
1000
    {
1001 47802
        return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY);
1002
    }
1003
1004
    /**
1005
     * Returns the SQL to subtract the number of given days to a date.
1006
     *
1007
     * @param string $date SQL expression producing the date.
1008
     * @param string $days SQL expression producing the number of days.
1009
     *
1010
     * @throws DBALException If not supported on this platform.
1011
     */
1012 47756
    public function getDateSubDaysExpression(string $date, string $days) : string
1013
    {
1014 47756
        return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY);
1015
    }
1016
1017
    /**
1018
     * Returns the SQL to add the number of given weeks to a date.
1019
     *
1020
     * @param string $date  SQL expression producing the date.
1021
     * @param string $weeks SQL expression producing the number of weeks.
1022
     *
1023
     * @throws DBALException If not supported on this platform.
1024
     */
1025 47710
    public function getDateAddWeeksExpression(string $date, string $weeks) : string
1026
    {
1027 47710
        return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK);
1028
    }
1029
1030
    /**
1031
     * Returns the SQL to subtract the number of given weeks from a date.
1032
     *
1033
     * @param string $date  SQL expression producing the date.
1034
     * @param string $weeks SQL expression producing the number of weeks.
1035
     *
1036
     * @throws DBALException If not supported on this platform.
1037
     */
1038 47664
    public function getDateSubWeeksExpression(string $date, string $weeks) : string
1039
    {
1040 47664
        return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK);
1041
    }
1042
1043
    /**
1044
     * Returns the SQL to add the number of given months to a date.
1045
     *
1046
     * @param string $date   SQL expression producing the date.
1047
     * @param string $months SQL expression producing the number of months.
1048
     *
1049
     * @throws DBALException If not supported on this platform.
1050
     */
1051 47618
    public function getDateAddMonthExpression(string $date, string $months) : string
1052
    {
1053 47618
        return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH);
1054
    }
1055
1056
    /**
1057
     * Returns the SQL to subtract the number of given months to a date.
1058
     *
1059
     * @param string $date   SQL expression producing the date.
1060
     * @param string $months SQL expression producing the number of months.
1061
     *
1062
     * @throws DBALException If not supported on this platform.
1063
     */
1064 47572
    public function getDateSubMonthExpression(string $date, string $months) : string
1065
    {
1066 47572
        return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH);
1067
    }
1068
1069
    /**
1070
     * Returns the SQL to add the number of given quarters to a date.
1071
     *
1072
     * @param string $date     SQL expression producing the date.
1073
     * @param string $quarters SQL expression producing the number of quarters.
1074
     *
1075
     * @throws DBALException If not supported on this platform.
1076
     */
1077 47526
    public function getDateAddQuartersExpression(string $date, string $quarters) : string
1078
    {
1079 47526
        return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER);
1080
    }
1081
1082
    /**
1083
     * Returns the SQL to subtract the number of given quarters from a date.
1084
     *
1085
     * @param string $date     SQL expression producing the date.
1086
     * @param string $quarters SQL expression producing the number of quarters.
1087
     *
1088
     * @throws DBALException If not supported on this platform.
1089
     */
1090 47480
    public function getDateSubQuartersExpression(string $date, string $quarters) : string
1091
    {
1092 47480
        return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER);
1093
    }
1094
1095
    /**
1096
     * Returns the SQL to add the number of given years to a date.
1097
     *
1098
     * @param string $date  SQL expression producing the date.
1099
     * @param string $years SQL expression producing the number of years.
1100
     *
1101
     * @throws DBALException If not supported on this platform.
1102
     */
1103 47434
    public function getDateAddYearsExpression(string $date, string $years) : string
1104
    {
1105 47434
        return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR);
1106
    }
1107
1108
    /**
1109
     * Returns the SQL to subtract the number of given years from a date.
1110
     *
1111
     * @param string $date  SQL expression producing the date.
1112
     * @param string $years SQL expression producing the number of years.
1113
     *
1114
     * @throws DBALException If not supported on this platform.
1115
     */
1116 47388
    public function getDateSubYearsExpression(string $date, string $years) : string
1117
    {
1118 47388
        return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR);
1119
    }
1120
1121
    /**
1122
     * Returns the SQL for a date arithmetic expression.
1123
     *
1124
     * @param string $date     SQL expression representing a date to perform the arithmetic operation on.
1125
     * @param string $operator The arithmetic operator (+ or -).
1126
     * @param string $interval SQL expression representing the value of the interval that shall be calculated
1127
     *                         into the date.
1128
     * @param string $unit     The unit of the interval that shall be calculated into the date.
1129
     *                         One of the DATE_INTERVAL_UNIT_* constants.
1130
     *
1131
     * @throws DBALException If not supported on this platform.
1132
     */
1133
    protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string
0 ignored issues
show
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

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

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

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

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...
1134
    {
1135
        throw DBALException::notSupported(__METHOD__);
1136
    }
1137
1138
    /**
1139
     * Generates the SQL expression which represents the given date interval multiplied by a number
1140
     *
1141
     * @param string $interval   SQL expression describing the interval value
1142
     * @param int    $multiplier Interval multiplier
1143
     *
1144
     * @throws DBALException
1145
     */
1146 44451
    protected function multiplyInterval(string $interval, int $multiplier) : string
1147
    {
1148 44451
        return sprintf('(%s * %d)', $interval, $multiplier);
1149
    }
1150
1151
    /**
1152
     * Returns the SQL bit AND comparison expression.
1153
     *
1154
     * @param string $value1 SQL expression producing the first value.
1155
     * @param string $value2 SQL expression producing the second value.
1156
     */
1157 46946
    public function getBitAndComparisonExpression(string $value1, string $value2) : string
1158
    {
1159 46946
        return '(' . $value1 . ' & ' . $value2 . ')';
1160
    }
1161
1162
    /**
1163
     * Returns the SQL bit OR comparison expression.
1164
     *
1165
     * @param string $value1 SQL expression producing the first value.
1166
     * @param string $value2 SQL expression producing the second value.
1167
     */
1168 46945
    public function getBitOrComparisonExpression(string $value1, string $value2) : string
1169
    {
1170 46945
        return '(' . $value1 . ' | ' . $value2 . ')';
1171
    }
1172
1173
    /**
1174
     * Returns the FOR UPDATE expression.
1175
     *
1176
     * @return string
1177
     */
1178 38422
    public function getForUpdateSQL()
1179
    {
1180 38422
        return 'FOR UPDATE';
1181
    }
1182
1183
    /**
1184
     * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
1185
     *
1186
     * @param string   $fromClause The FROM clause to append the hint for the given lock mode to.
1187
     * @param int|null $lockMode   One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will
1188
     *                             be appended to the FROM clause.
1189
     *
1190
     * @return string
1191
     */
1192 40343
    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

1192
    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...
1193
    {
1194 40343
        return $fromClause;
1195
    }
1196
1197
    /**
1198
     * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
1199
     *
1200
     * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
1201
     * vendors allow to lighten this constraint up to be a real read lock.
1202
     *
1203
     * @return string
1204
     */
1205
    public function getReadLockSQL()
1206
    {
1207
        return $this->getForUpdateSQL();
1208
    }
1209
1210
    /**
1211
     * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
1212
     *
1213
     * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
1214
     *
1215
     * @return string
1216
     */
1217 44186
    public function getWriteLockSQL()
1218
    {
1219 44186
        return $this->getForUpdateSQL();
1220
    }
1221
1222
    /**
1223
     * Returns the SQL snippet to drop an existing database.
1224
     *
1225
     * @param string $database The name of the database that should be dropped.
1226
     *
1227
     * @return string
1228
     */
1229 33444
    public function getDropDatabaseSQL($database)
1230
    {
1231 33444
        return 'DROP DATABASE ' . $database;
1232
    }
1233
1234
    /**
1235
     * Returns the SQL snippet to drop an existing table.
1236
     *
1237
     * @param Table|string $table
1238
     *
1239
     * @return string
1240
     *
1241
     * @throws InvalidArgumentException
1242
     */
1243 49107
    public function getDropTableSQL($table)
1244
    {
1245 49107
        $tableArg = $table;
1246
1247 49107
        if ($table instanceof Table) {
1248 4968
            $table = $table->getQuotedName($this);
1249
        }
1250
1251 49107
        if (! is_string($table)) {
0 ignored issues
show
introduced by
The condition is_string($table) is always true.
Loading history...
1252
            throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
1253
        }
1254
1255 49107
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
1256 41722
            $eventArgs = new SchemaDropTableEventArgs($tableArg, $this);
1257 41722
            $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
1258
1259 41722
            if ($eventArgs->isDefaultPrevented()) {
1260
                $sql = $eventArgs->getSql();
1261
1262
                if ($sql === null) {
1263
                    throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL');
1264
                }
1265
1266
                return $sql;
1267
            }
1268
        }
1269
1270 49107
        return 'DROP TABLE ' . $table;
1271
    }
1272
1273
    /**
1274
     * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
1275
     *
1276
     * @param Table|string $table
1277
     *
1278
     * @return string
1279
     */
1280 17281
    public function getDropTemporaryTableSQL($table)
1281
    {
1282 17281
        return $this->getDropTableSQL($table);
1283
    }
1284
1285
    /**
1286
     * Returns the SQL to drop an index from a table.
1287
     *
1288
     * @param Index|string $index
1289
     * @param Table|string $table
1290
     *
1291
     * @return string
1292
     *
1293
     * @throws InvalidArgumentException
1294
     */
1295 32298
    public function getDropIndexSQL($index, $table = null)
1296
    {
1297 32298
        if ($index instanceof Index) {
1298 32276
            $index = $index->getQuotedName($this);
1299 13834
        } elseif (! is_string($index)) {
0 ignored issues
show
introduced by
The condition is_string($index) is always true.
Loading history...
1300
            throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
1301
        }
1302
1303 32298
        return 'DROP INDEX ' . $index;
1304
    }
1305
1306
    /**
1307
     * Returns the SQL to drop a constraint.
1308
     *
1309
     * @param Constraint|string $constraint
1310
     * @param Table|string      $table
1311
     *
1312
     * @return string
1313
     */
1314 42143
    public function getDropConstraintSQL($constraint, $table)
1315
    {
1316 42143
        if (! $constraint instanceof Constraint) {
1317 41032
            $constraint = new Identifier($constraint);
1318
        }
1319
1320 42143
        if (! $table instanceof Table) {
1321 42143
            $table = new Identifier($table);
1322
        }
1323
1324 42143
        $constraint = $constraint->getQuotedName($this);
1325 42143
        $table      = $table->getQuotedName($this);
1326
1327 42143
        return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
1328
    }
1329
1330
    /**
1331
     * Returns the SQL to drop a foreign key.
1332
     *
1333
     * @param ForeignKeyConstraint|string $foreignKey
1334
     * @param Table|string                $table
1335
     *
1336
     * @return string
1337
     */
1338 43772
    public function getDropForeignKeySQL($foreignKey, $table)
1339
    {
1340 43772
        if (! $foreignKey instanceof ForeignKeyConstraint) {
1341 41055
            $foreignKey = new Identifier($foreignKey);
1342
        }
1343
1344 43772
        if (! $table instanceof Table) {
1345 43772
            $table = new Identifier($table);
1346
        }
1347
1348 43772
        $foreignKey = $foreignKey->getQuotedName($this);
1349 43772
        $table      = $table->getQuotedName($this);
1350
1351 43772
        return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
1352
    }
1353
1354
    /**
1355
     * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
1356
     * on this platform.
1357
     *
1358
     * @param int $createFlags
1359
     *
1360
     * @return string[] The sequence of SQL statements.
1361
     *
1362
     * @throws DBALException
1363
     * @throws InvalidArgumentException
1364
     */
1365 49107
    public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES)
1366
    {
1367 49107
        if (! is_int($createFlags)) {
0 ignored issues
show
introduced by
The condition is_int($createFlags) is always true.
Loading history...
1368
            throw new InvalidArgumentException('Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.');
1369
        }
1370
1371 49107
        if (count($table->getColumns()) === 0) {
1372 41998
            throw DBALException::noColumnsSpecifiedForTable($table->getName());
1373
        }
1374
1375 49107
        $tableName                    = $table->getQuotedName($this);
1376 49107
        $options                      = $table->getOptions();
1377 49107
        $options['uniqueConstraints'] = [];
1378 49107
        $options['indexes']           = [];
1379 49107
        $options['primary']           = [];
1380
1381 49107
        if (($createFlags & self::CREATE_INDEXES) > 0) {
1382 49107
            foreach ($table->getIndexes() as $index) {
1383
                /** @var $index Index */
1384 49107
                if (! $index->isPrimary()) {
1385 47075
                    $options['indexes'][$index->getQuotedName($this)] = $index;
1386
1387 47075
                    continue;
1388
                }
1389
1390 49107
                $options['primary']       = $index->getQuotedColumns($this);
1391 49107
                $options['primary_index'] = $index;
1392
            }
1393
1394 49107
            foreach ($table->getUniqueConstraints() as $uniqueConstraint) {
1395
                /** @var UniqueConstraint $uniqueConstraint */
1396
                $options['uniqueConstraints'][$uniqueConstraint->getQuotedName($this)] = $uniqueConstraint;
1397
            }
1398
        }
1399
1400 49107
        if (($createFlags & self::CREATE_FOREIGNKEYS) > 0) {
1401 49107
            $options['foreignKeys'] = [];
1402
1403 49107
            foreach ($table->getForeignKeys() as $fkConstraint) {
1404 47063
                $options['foreignKeys'][] = $fkConstraint;
1405
            }
1406
        }
1407
1408 49107
        $columnSql = [];
1409 49107
        $columns   = [];
1410
1411 49107
        foreach ($table->getColumns() as $column) {
1412 49107
            if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) {
1413 41745
                $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this);
1414 41745
                $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs);
1415
1416 41745
                $columnSql = array_merge($columnSql, $eventArgs->getSql());
1417
1418 41745
                if ($eventArgs->isDefaultPrevented()) {
1419
                    continue;
1420
                }
1421
            }
1422
1423 49107
            $columnData            = $column->toArray();
1424 49107
            $columnData['name']    = $column->getQuotedName($this);
1425 49107
            $columnData['version'] = $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false;
1426 49107
            $columnData['comment'] = $this->getColumnComment($column);
1427
1428 49107
            if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) {
1429 48817
                $columnData['length'] = 255;
1430
            }
1431
1432 49107
            if (in_array($column->getName(), $options['primary'])) {
1433 49107
                $columnData['primary'] = true;
1434
            }
1435
1436 49107
            $columns[$columnData['name']] = $columnData;
1437
        }
1438
1439 49107
        if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
1440 41745
            $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
1441 41745
            $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
1442
1443 41745
            if ($eventArgs->isDefaultPrevented()) {
1444
                return array_merge($eventArgs->getSql(), $columnSql);
1445
            }
1446
        }
1447
1448 49107
        $sql = $this->_getCreateTableSQL($tableName, $columns, $options);
1449 49107
        if ($this->supportsCommentOnStatement()) {
1450 45057
            foreach ($table->getColumns() as $column) {
1451 45057
                $comment = $this->getColumnComment($column);
1452
1453 45057
                if ($comment === null || $comment === '') {
1454 45057
                    continue;
1455
                }
1456
1457 42775
                $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment);
1458
            }
1459
        }
1460
1461 49107
        return array_merge($sql, $columnSql);
1462
    }
1463
1464
    /**
1465
     * @param string      $tableName
1466
     * @param string      $columnName
1467
     * @param string|null $comment
1468
     *
1469
     * @return string
1470
     */
1471 41844
    public function getCommentOnColumnSQL($tableName, $columnName, $comment)
1472
    {
1473 41844
        $tableName  = new Identifier($tableName);
1474 41844
        $columnName = new Identifier($columnName);
1475
1476 41844
        return sprintf(
1477
            'COMMENT ON COLUMN %s.%s IS %s',
1478 41844
            $tableName->getQuotedName($this),
1479 41844
            $columnName->getQuotedName($this),
1480 41844
            $this->quoteStringLiteral((string) $comment)
1481
        );
1482
    }
1483
1484
    /**
1485
     * Returns the SQL to create inline comment on a column.
1486
     *
1487
     * @param string $comment
1488
     *
1489
     * @return string
1490
     *
1491
     * @throws DBALException If not supported on this platform.
1492
     */
1493 43931
    public function getInlineColumnCommentSQL($comment)
1494
    {
1495 43931
        if (! $this->supportsInlineColumnComments()) {
1496 40940
            throw DBALException::notSupported(__METHOD__);
1497
        }
1498
1499 43022
        return 'COMMENT ' . $this->quoteStringLiteral($comment);
1500
    }
1501
1502
    /**
1503
     * Returns the SQL used to create a table.
1504
     *
1505
     * @param string    $tableName
1506
     * @param mixed[][] $columns
1507
     * @param mixed[]   $options
1508
     *
1509
     * @return string[]
1510
     */
1511 43491
    protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
1512
    {
1513 43491
        $columnListSql = $this->getColumnDeclarationListSQL($columns);
1514
1515 43491
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
1516
            foreach ($options['uniqueConstraints'] as $name => $definition) {
1517
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
1518
            }
1519
        }
1520
1521 43491
        if (isset($options['primary']) && ! empty($options['primary'])) {
1522 43491
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
1523
        }
1524
1525 43491
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
1526
            foreach ($options['indexes'] as $index => $definition) {
1527
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
1528
            }
1529
        }
1530
1531 43491
        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
1532
1533 43491
        $check = $this->getCheckDeclarationSQL($columns);
1534 43491
        if (! empty($check)) {
1535 43240
            $query .= ', ' . $check;
1536
        }
1537 43491
        $query .= ')';
1538
1539 43491
        $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...
1540
1541 43491
        if (isset($options['foreignKeys'])) {
1542 43469
            foreach ((array) $options['foreignKeys'] as $definition) {
1543 43352
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
1544
            }
1545
        }
1546
1547 43491
        return $sql;
1548
    }
1549
1550
    /**
1551
     * @return string
1552
     */
1553 38382
    public function getCreateTemporaryTableSnippetSQL()
1554
    {
1555 38382
        return 'CREATE TEMPORARY TABLE';
1556
    }
1557
1558
    /**
1559
     * Returns the SQL to create a sequence on this platform.
1560
     *
1561
     * @return string
1562
     *
1563
     * @throws DBALException If not supported on this platform.
1564
     */
1565
    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

1565
    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...
1566
    {
1567
        throw DBALException::notSupported(__METHOD__);
1568
    }
1569
1570
    /**
1571
     * Returns the SQL to change a sequence on this platform.
1572
     *
1573
     * @return string
1574
     *
1575
     * @throws DBALException If not supported on this platform.
1576
     */
1577
    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

1577
    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...
1578
    {
1579
        throw DBALException::notSupported(__METHOD__);
1580
    }
1581
1582
    /**
1583
     * Returns the SQL to create a constraint on a table on this platform.
1584
     *
1585
     * @param Table|string $table
1586
     *
1587
     * @return string
1588
     *
1589
     * @throws InvalidArgumentException
1590
     */
1591 41860
    public function getCreateConstraintSQL(Constraint $constraint, $table)
1592
    {
1593 41860
        if ($table instanceof Table) {
1594
            $table = $table->getQuotedName($this);
1595
        }
1596
1597 41860
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this);
1598
1599 41860
        $columnList = '(' . implode(', ', $constraint->getQuotedColumns($this)) . ')';
1600
1601 41860
        $referencesClause = '';
1602 41860
        if ($constraint instanceof Index) {
1603 41860
            if ($constraint->isPrimary()) {
1604 41860
                $query .= ' PRIMARY KEY';
1605 41860
            } elseif ($constraint->isUnique()) {
1606 41860
                $query .= ' UNIQUE';
1607
            } else {
1608
                throw new InvalidArgumentException(
1609 41860
                    'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
1610
                );
1611
            }
1612 41860
        } elseif ($constraint instanceof ForeignKeyConstraint) {
1613 41860
            $query .= ' FOREIGN KEY';
1614
1615 41860
            $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) .
1616 41860
                ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')';
1617
        }
1618 41860
        $query .= ' ' . $columnList . $referencesClause;
1619
1620 41860
        return $query;
1621
    }
1622
1623
    /**
1624
     * Returns the SQL to create an index on a table on this platform.
1625
     *
1626
     * @param Table|string $table The name of the table on which the index is to be created.
1627
     *
1628
     * @return string
1629
     *
1630
     * @throws InvalidArgumentException
1631
     */
1632 45907
    public function getCreateIndexSQL(Index $index, $table)
1633
    {
1634 45907
        if ($table instanceof Table) {
1635 45431
            $table = $table->getQuotedName($this);
1636
        }
1637 45907
        $name    = $index->getQuotedName($this);
1638 45907
        $columns = $index->getColumns();
1639
1640 45907
        if (count($columns) === 0) {
1641
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
1642
        }
1643
1644 45907
        if ($index->isPrimary()) {
1645 40112
            return $this->getCreatePrimaryKeySQL($index, $table);
1646
        }
1647
1648 45907
        $query  = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table;
1649 45907
        $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index);
1650
1651 45907
        return $query;
1652
    }
1653
1654
    /**
1655
     * Adds condition for partial index.
1656
     *
1657
     * @return string
1658
     */
1659 47075
    protected function getPartialIndexSQL(Index $index)
1660
    {
1661 47075
        if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
1662 30739
            return ' WHERE ' . $index->getOption('where');
1663
        }
1664
1665 47075
        return '';
1666
    }
1667
1668
    /**
1669
     * Adds additional flags for index generation.
1670
     *
1671
     * @return string
1672
     */
1673 44416
    protected function getCreateIndexSQLFlags(Index $index)
1674
    {
1675 44416
        return $index->isUnique() ? 'UNIQUE ' : '';
1676
    }
1677
1678
    /**
1679
     * Returns the SQL to create an unnamed primary key constraint.
1680
     *
1681
     * @param Table|string $table
1682
     *
1683
     * @return string
1684
     */
1685 43148
    public function getCreatePrimaryKeySQL(Index $index, $table)
1686
    {
1687 43148
        if ($table instanceof Table) {
1688
            $table = $table->getQuotedName($this);
1689
        }
1690
1691 43148
        return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')';
1692
    }
1693
1694
    /**
1695
     * Returns the SQL to create a named schema.
1696
     *
1697
     * @param string $schemaName
1698
     *
1699
     * @return string
1700
     *
1701
     * @throws DBALException If not supported on this platform.
1702
     */
1703 41308
    public function getCreateSchemaSQL($schemaName)
1704
    {
1705 41308
        throw DBALException::notSupported(__METHOD__);
1706
    }
1707
1708
    /**
1709
     * Quotes a string so that it can be safely used as a table or column name,
1710
     * even if it is a reserved word of the platform. This also detects identifier
1711
     * chains separated by dot and quotes them independently.
1712
     *
1713
     * NOTE: Just because you CAN use quoted identifiers doesn't mean
1714
     * you SHOULD use them. In general, they end up causing way more
1715
     * problems than they solve.
1716
     *
1717
     * @param string $str The identifier name to be quoted.
1718
     *
1719
     * @return string The quoted identifier string.
1720
     */
1721 48794
    public function quoteIdentifier($str)
1722
    {
1723 48794
        if (strpos($str, '.') !== false) {
1724 43179
            $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str));
1725
1726 43179
            return implode('.', $parts);
1727
        }
1728
1729 48794
        return $this->quoteSingleIdentifier($str);
1730
    }
1731
1732
    /**
1733
     * Quotes a single identifier (no dot chain separation).
1734
     *
1735
     * @param string $str The identifier name to be quoted.
1736
     *
1737
     * @return string The quoted identifier string.
1738
     */
1739 48374
    public function quoteSingleIdentifier($str)
1740
    {
1741 48374
        $c = $this->getIdentifierQuoteCharacter();
1742
1743 48374
        return $c . str_replace($c, $c . $c, $str) . $c;
1744
    }
1745
1746
    /**
1747
     * Returns the SQL to create a new foreign key.
1748
     *
1749
     * @param ForeignKeyConstraint $foreignKey The foreign key constraint.
1750
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
1751
     *
1752
     * @return string
1753
     */
1754 47063
    public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
1755
    {
1756 47063
        if ($table instanceof Table) {
1757 2737
            $table = $table->getQuotedName($this);
1758
        }
1759
1760 47063
        return 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
1761
    }
1762
1763
    /**
1764
     * Gets the SQL statements for altering an existing table.
1765
     *
1766
     * This method returns an array of SQL statements, since some platforms need several statements.
1767
     *
1768
     * @return string[]
1769
     *
1770
     * @throws DBALException If not supported on this platform.
1771
     */
1772
    public function getAlterTableSQL(TableDiff $diff)
1773
    {
1774
        throw DBALException::notSupported(__METHOD__);
1775
    }
1776
1777
    /**
1778
     * @param mixed[] $columnSql
1779
     *
1780
     * @return bool
1781
     */
1782 46159
    protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql)
1783
    {
1784 46159
        if ($this->_eventManager === null) {
1785 41791
            return false;
1786
        }
1787
1788 46159
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
1789 46159
            return false;
1790
        }
1791
1792 41699
        $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this);
1793 41699
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs);
1794
1795 41699
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1796
1797 41699
        return $eventArgs->isDefaultPrevented();
1798
    }
1799
1800
    /**
1801
     * @param string[] $columnSql
1802
     *
1803
     * @return bool
1804
     */
1805 45387
    protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql)
1806
    {
1807 45387
        if ($this->_eventManager === null) {
1808 41791
            return false;
1809
        }
1810
1811 45387
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
1812 45387
            return false;
1813
        }
1814
1815 41699
        $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this);
1816 41699
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs);
1817
1818 41699
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1819
1820 41699
        return $eventArgs->isDefaultPrevented();
1821
    }
1822
1823
    /**
1824
     * @param string[] $columnSql
1825
     *
1826
     * @return bool
1827
     */
1828 45988
    protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql)
1829
    {
1830 45988
        if ($this->_eventManager === null) {
1831 42941
            return false;
1832
        }
1833
1834 45988
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
1835 45988
            return false;
1836
        }
1837
1838 41699
        $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this);
1839 41699
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs);
1840
1841 41699
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1842
1843 41699
        return $eventArgs->isDefaultPrevented();
1844
    }
1845
1846
    /**
1847
     * @param string   $oldColumnName
1848
     * @param string[] $columnSql
1849
     *
1850
     * @return bool
1851
     */
1852 45293
    protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql)
1853
    {
1854 45293
        if ($this->_eventManager === null) {
1855 41124
            return false;
1856
        }
1857
1858 45293
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
1859 45293
            return false;
1860
        }
1861
1862 41699
        $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this);
1863 41699
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs);
1864
1865 41699
        $columnSql = array_merge($columnSql, $eventArgs->getSql());
1866
1867 41699
        return $eventArgs->isDefaultPrevented();
1868
    }
1869
1870
    /**
1871
     * @param string[] $sql
1872
     *
1873
     * @return bool
1874
     */
1875 46372
    protected function onSchemaAlterTable(TableDiff $diff, &$sql)
1876
    {
1877 46372
        if ($this->_eventManager === null) {
1878 42941
            return false;
1879
        }
1880
1881 46372
        if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
1882 46372
            return false;
1883
        }
1884
1885 41699
        $eventArgs = new SchemaAlterTableEventArgs($diff, $this);
1886 41699
        $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs);
1887
1888 41699
        $sql = array_merge($sql, $eventArgs->getSql());
1889
1890 41699
        return $eventArgs->isDefaultPrevented();
1891
    }
1892
1893
    /**
1894
     * @return string[]
1895
     */
1896 46372
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
1897
    {
1898 46372
        $tableName = $diff->getName($this)->getQuotedName($this);
1899
1900 46372
        $sql = [];
1901 46372
        if ($this->supportsForeignKeyConstraints()) {
1902 46372
            foreach ($diff->removedForeignKeys as $foreignKey) {
1903 45245
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
1904
            }
1905 46372
            foreach ($diff->changedForeignKeys as $foreignKey) {
1906 40871
                $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
1907
            }
1908
        }
1909
1910 46372
        foreach ($diff->removedIndexes as $index) {
1911 45779
            $sql[] = $this->getDropIndexSQL($index, $tableName);
1912
        }
1913 46372
        foreach ($diff->changedIndexes as $index) {
1914 45345
            $sql[] = $this->getDropIndexSQL($index, $tableName);
1915
        }
1916
1917 46372
        return $sql;
1918
    }
1919
1920
    /**
1921
     * @return string[]
1922
     */
1923 46372
    protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
1924
    {
1925 46372
        $sql     = [];
1926 46372
        $newName = $diff->getNewName();
1927
1928 46372
        if ($newName !== false) {
1929 42143
            $tableName = $newName->getQuotedName($this);
1930
        } else {
1931 46372
            $tableName = $diff->getName($this)->getQuotedName($this);
1932
        }
1933
1934 46372
        if ($this->supportsForeignKeyConstraints()) {
1935 46372
            foreach ($diff->addedForeignKeys as $foreignKey) {
1936 45345
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
1937
            }
1938
1939 46372
            foreach ($diff->changedForeignKeys as $foreignKey) {
1940 40871
                $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
1941
            }
1942
        }
1943
1944 46372
        foreach ($diff->addedIndexes as $index) {
1945 45345
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
1946
        }
1947
1948 46372
        foreach ($diff->changedIndexes as $index) {
1949 45345
            $sql[] = $this->getCreateIndexSQL($index, $tableName);
1950
        }
1951
1952 46372
        foreach ($diff->renamedIndexes as $oldIndexName => $index) {
1953 45345
            $oldIndexName = new Identifier($oldIndexName);
1954 45345
            $sql          = array_merge(
1955 45345
                $sql,
1956 45345
                $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName)
1957
            );
1958
        }
1959
1960 46372
        return $sql;
1961
    }
1962
1963
    /**
1964
     * Returns the SQL for renaming an index on a table.
1965
     *
1966
     * @param string $oldIndexName The name of the index to rename from.
1967
     * @param Index  $index        The definition of the index to rename to.
1968
     * @param string $tableName    The table to rename the given index on.
1969
     *
1970
     * @return string[] The sequence of SQL statements for renaming the given index.
1971
     */
1972 41256
    protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName)
1973
    {
1974
        return [
1975 41256
            $this->getDropIndexSQL($oldIndexName, $tableName),
1976 41256
            $this->getCreateIndexSQL($index, $tableName),
1977
        ];
1978
    }
1979
1980
    /**
1981
     * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
1982
     *
1983
     * @return string[]
1984
     */
1985
    protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
1986
    {
1987
        return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff));
1988
    }
1989
1990
    /**
1991
     * Gets declaration of a number of fields in bulk.
1992
     *
1993
     * @param mixed[][] $fields A multidimensional associative array.
1994
     *                          The first dimension determines the field name, while the second
1995
     *                          dimension is keyed with the name of the properties
1996
     *                          of the field being declared as array indexes. Currently, the types
1997
     *                          of supported field properties are as follows:
1998
     *
1999
     *      length
2000
     *          Integer value that determines the maximum length of the text
2001
     *          field. If this argument is missing the field should be
2002
     *          declared to have the longest length allowed by the DBMS.
2003
     *
2004
     *      default
2005
     *          Text value to be used as default for this field.
2006
     *
2007
     *      notnull
2008
     *          Boolean flag that indicates whether this field is constrained
2009
     *          to not be set to null.
2010
     *      charset
2011
     *          Text value with the default CHARACTER SET for this field.
2012
     *      collation
2013
     *          Text value with the default COLLATION for this field.
2014
     *      unique
2015
     *          unique constraint
2016
     *
2017
     * @return string
2018
     */
2019 49107
    public function getColumnDeclarationListSQL(array $fields)
2020
    {
2021 49107
        $queryFields = [];
2022
2023 49107
        foreach ($fields as $fieldName => $field) {
2024 49107
            $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field);
2025
        }
2026
2027 49107
        return implode(', ', $queryFields);
2028
    }
2029
2030
    /**
2031
     * Obtains DBMS specific SQL code portion needed to declare a generic type
2032
     * field to be used in statements like CREATE TABLE.
2033
     *
2034
     * @param string  $name  The name the field to be declared.
2035
     * @param mixed[] $field An associative array with the name of the properties
2036
     *                       of the field being declared as array indexes. Currently, the types
2037
     *                       of supported field properties are as follows:
2038
     *
2039
     *      length
2040
     *          Integer value that determines the maximum length of the text
2041
     *          field. If this argument is missing the field should be
2042
     *          declared to have the longest length allowed by the DBMS.
2043
     *
2044
     *      default
2045
     *          Text value to be used as default for this field.
2046
     *
2047
     *      notnull
2048
     *          Boolean flag that indicates whether this field is constrained
2049
     *          to not be set to null.
2050
     *      charset
2051
     *          Text value with the default CHARACTER SET for this field.
2052
     *      collation
2053
     *          Text value with the default COLLATION for this field.
2054
     *      unique
2055
     *          unique constraint
2056
     *      check
2057
     *          column check constraint
2058
     *      columnDefinition
2059
     *          a string that defines the complete column
2060
     *
2061
     * @return string DBMS specific SQL code portion that should be used to declare the column.
2062
     */
2063 48715
    public function getColumnDeclarationSQL($name, array $field)
2064
    {
2065 48715
        if (isset($field['columnDefinition'])) {
2066 43719
            $columnDef = $this->getCustomTypeDeclarationSQL($field);
2067
        } else {
2068 48715
            $default = $this->getDefaultValueDeclarationSQL($field);
2069
2070 48715
            $charset = isset($field['charset']) && $field['charset'] ?
2071 48715
                ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
2072
2073 48715
            $collation = isset($field['collation']) && $field['collation'] ?
2074 48715
                ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
2075
2076 48715
            $notnull = isset($field['notnull']) && $field['notnull'] ? ' NOT NULL' : '';
2077
2078 48715
            $unique = isset($field['unique']) && $field['unique'] ?
2079 48715
                ' ' . $this->getUniqueFieldDeclarationSQL() : '';
2080
2081 48715
            $check = isset($field['check']) && $field['check'] ?
2082 48715
                ' ' . $field['check'] : '';
2083
2084 48715
            $typeDecl  = $field['type']->getSQLDeclaration($field, $this);
2085 48715
            $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
2086
2087 48715
            if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') {
2088 43022
                $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']);
2089
            }
2090
        }
2091
2092 48715
        return $name . ' ' . $columnDef;
2093
    }
2094
2095
    /**
2096
     * Returns the SQL snippet that declares a floating point column of arbitrary precision.
2097
     *
2098
     * @param mixed[] $columnDef
2099
     *
2100
     * @return string
2101
     */
2102 45841
    public function getDecimalTypeDeclarationSQL(array $columnDef)
2103
    {
2104 45841
        $columnDef['precision'] = ! isset($columnDef['precision']) || empty($columnDef['precision'])
2105 45841
            ? 10 : $columnDef['precision'];
2106 45841
        $columnDef['scale']     = ! isset($columnDef['scale']) || empty($columnDef['scale'])
2107 45841
            ? 0 : $columnDef['scale'];
2108
2109 45841
        return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
2110
    }
2111
2112
    /**
2113
     * Obtains DBMS specific SQL code portion needed to set a default value
2114
     * declaration to be used in statements like CREATE TABLE.
2115
     *
2116
     * @param mixed[] $field The field definition array.
2117
     *
2118
     * @return string DBMS specific SQL code portion needed to set a default value.
2119
     */
2120 48715
    public function getDefaultValueDeclarationSQL($field)
2121
    {
2122 48715
        if (! isset($field['default'])) {
2123 48715
            return empty($field['notnull']) ? ' DEFAULT NULL' : '';
2124
        }
2125
2126 45906
        $default = $field['default'];
2127
2128 45906
        if (! isset($field['type'])) {
2129
            return " DEFAULT '" . $default . "'";
2130
        }
2131
2132 45906
        $type = $field['type'];
2133
2134 45906
        if ($type instanceof Types\PhpIntegerMappingType) {
2135 45802
            return ' DEFAULT ' . $default;
2136
        }
2137
2138 45885
        if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
2139 44127
            return ' DEFAULT ' . $this->getCurrentTimestampSQL();
2140
        }
2141
2142 45885
        if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
2143 7952
            return ' DEFAULT ' . $this->getCurrentTimeSQL();
2144
        }
2145
2146 45885
        if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
2147 42266
            return ' DEFAULT ' . $this->getCurrentDateSQL();
2148
        }
2149
2150 45885
        if ($type instanceof Types\BooleanType) {
2151 45801
            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

2151
            return " DEFAULT '" . /** @scrutinizer ignore-type */ $this->convertBooleans($default) . "'";
Loading history...
2152
        }
2153
2154 45554
        return " DEFAULT '" . $default . "'";
2155
    }
2156
2157
    /**
2158
     * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
2159
     * declaration to be used in statements like CREATE TABLE.
2160
     *
2161
     * @param string[]|mixed[][] $definition The check definition.
2162
     *
2163
     * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
2164
     */
2165 43883
    public function getCheckDeclarationSQL(array $definition)
2166
    {
2167 43883
        $constraints = [];
2168 43883
        foreach ($definition as $field => $def) {
2169 43883
            if (is_string($def)) {
2170
                $constraints[] = 'CHECK (' . $def . ')';
2171
            } else {
2172 43883
                if (isset($def['min'])) {
2173 43240
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
2174
                }
2175
2176 43883
                if (isset($def['max'])) {
2177 43240
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
2178
                }
2179
            }
2180
        }
2181
2182 43883
        return implode(', ', $constraints);
2183
    }
2184
2185
    /**
2186
     * Obtains DBMS specific SQL code portion needed to set a unique
2187
     * constraint declaration to be used in statements like CREATE TABLE.
2188
     *
2189
     * @param string           $name       The name of the unique constraint.
2190
     * @param UniqueConstraint $constraint The unique constraint definition.
2191
     *
2192
     * @return string DBMS specific SQL code portion needed to set a constraint.
2193
     *
2194
     * @throws InvalidArgumentException
2195
     */
2196 41906
    public function getUniqueConstraintDeclarationSQL($name, UniqueConstraint $constraint)
2197
    {
2198 41906
        $columns = $constraint->getColumns();
2199 41906
        $name    = new Identifier($name);
2200
2201 41906
        if (count($columns) === 0) {
2202 15916
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2203
        }
2204
2205 41906
        $flags = ['UNIQUE'];
2206
2207 41906
        if ($constraint->hasFlag('clustered')) {
2208 15939
            $flags[] = 'CLUSTERED';
2209
        }
2210
2211 41906
        $constraintName  = $name->getQuotedName($this);
2212 41906
        $constraintName  = ! empty($constraintName) ? $constraintName . ' ' : '';
2213 41906
        $columnListNames = $this->getIndexFieldDeclarationListSQL($columns);
2214
2215 41906
        return sprintf('CONSTRAINT %s%s (%s)', $constraintName, implode(' ', $flags), $columnListNames);
2216
    }
2217
2218
    /**
2219
     * Obtains DBMS specific SQL code portion needed to set an index
2220
     * declaration to be used in statements like CREATE TABLE.
2221
     *
2222
     * @param string $name  The name of the index.
2223
     * @param Index  $index The index definition.
2224
     *
2225
     * @return string DBMS specific SQL code portion needed to set an index.
2226
     *
2227
     * @throws InvalidArgumentException
2228
     */
2229 44541
    public function getIndexDeclarationSQL($name, Index $index)
2230
    {
2231 44541
        $columns = $index->getColumns();
2232 44541
        $name    = new Identifier($name);
2233
2234 44541
        if (count($columns) === 0) {
2235
            throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
2236
        }
2237
2238 44541
        return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' ('
2239 44541
            . $this->getIndexFieldDeclarationListSQL($index)
2240 44541
            . ')' . $this->getPartialIndexSQL($index);
2241
    }
2242
2243
    /**
2244
     * Obtains SQL code portion needed to create a custom column,
2245
     * e.g. when a field has the "columnDefinition" keyword.
2246
     * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
2247
     *
2248
     * @param mixed[] $columnDef
2249
     *
2250
     * @return string
2251
     */
2252 43719
    public function getCustomTypeDeclarationSQL(array $columnDef)
2253
    {
2254 43719
        return $columnDef['columnDefinition'];
2255
    }
2256
2257
    /**
2258
     * Obtains DBMS specific SQL code portion needed to set an index
2259
     * declaration to be used in statements like CREATE TABLE.
2260
     *
2261
     * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method
2262
     */
2263 47075
    public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string
2264
    {
2265 47075
        if ($columnsOrIndex instanceof Index) {
2266 47075
            return implode(', ', $columnsOrIndex->getQuotedColumns($this));
2267
        }
2268
2269 41906
        if (! is_array($columnsOrIndex)) {
0 ignored issues
show
introduced by
The condition is_array($columnsOrIndex) is always true.
Loading history...
2270
            throw new InvalidArgumentException('Fields argument should be an Index or array.');
2271
        }
2272
2273 41906
        $ret = [];
2274
2275 41906
        foreach ($columnsOrIndex as $column => $definition) {
2276 41906
            if (is_array($definition)) {
2277
                $ret[] = $column;
2278
            } else {
2279 41906
                $ret[] = $definition;
2280
            }
2281
        }
2282
2283 41906
        return implode(', ', $ret);
2284
    }
2285
2286
    /**
2287
     * Returns the required SQL string that fits between CREATE ... TABLE
2288
     * to create the table as a temporary table.
2289
     *
2290
     * Should be overridden in driver classes to return the correct string for the
2291
     * specific database type.
2292
     *
2293
     * The default is to return the string "TEMPORARY" - this will result in a
2294
     * SQL error for any database that does not support temporary tables, or that
2295
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
2296
     *
2297
     * @return string The string required to be placed between "CREATE" and "TABLE"
2298
     *                to generate a temporary table, if possible.
2299
     */
2300
    public function getTemporaryTableSQL()
2301
    {
2302
        return 'TEMPORARY';
2303
    }
2304
2305
    /**
2306
     * Some vendors require temporary table names to be qualified specially.
2307
     *
2308
     * @param string $tableName
2309
     *
2310
     * @return string
2311
     */
2312 38382
    public function getTemporaryTableName($tableName)
2313
    {
2314 38382
        return $tableName;
2315
    }
2316
2317
    /**
2318
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2319
     * of a field declaration to be used in statements like CREATE TABLE.
2320
     *
2321
     * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2322
     *                of a field declaration.
2323
     */
2324 47063
    public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
2325
    {
2326 47063
        $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
2327 47063
        $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
2328
2329 47063
        return $sql;
2330
    }
2331
2332
    /**
2333
     * Returns the FOREIGN KEY query section dealing with non-standard options
2334
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
2335
     *
2336
     * @param ForeignKeyConstraint $foreignKey The foreign key definition.
2337
     *
2338
     * @return string
2339
     */
2340 47063
    public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
2341
    {
2342 47063
        $query = '';
2343 47063
        if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
2344 15893
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
2345
        }
2346 47063
        if ($foreignKey->hasOption('onDelete')) {
2347 45558
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
2348
        }
2349
2350 47063
        return $query;
2351
    }
2352
2353
    /**
2354
     * Returns the given referential action in uppercase if valid, otherwise throws an exception.
2355
     *
2356
     * @param string $action The foreign key referential action.
2357
     *
2358
     * @return string
2359
     *
2360
     * @throws InvalidArgumentException If unknown referential action given.
2361
     */
2362 45558
    public function getForeignKeyReferentialActionSQL($action)
2363
    {
2364 45558
        $upper = strtoupper($action);
2365 45558
        switch ($upper) {
2366
            case 'CASCADE':
2367
            case 'SET NULL':
2368
            case 'NO ACTION':
2369
            case 'RESTRICT':
2370
            case 'SET DEFAULT':
2371 45558
                return $upper;
2372
            default:
2373 42504
                throw new InvalidArgumentException('Invalid foreign key action: ' . $upper);
2374
        }
2375
    }
2376
2377
    /**
2378
     * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
2379
     * of a field declaration to be used in statements like CREATE TABLE.
2380
     *
2381
     * @return string
2382
     *
2383
     * @throws InvalidArgumentException
2384
     */
2385 47063
    public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
2386
    {
2387 47063
        $sql = '';
2388 47063
        if (strlen($foreignKey->getName())) {
2389 47063
            $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' ';
2390
        }
2391 47063
        $sql .= 'FOREIGN KEY (';
2392
2393 47063
        if (count($foreignKey->getLocalColumns()) === 0) {
2394
            throw new InvalidArgumentException("Incomplete definition. 'local' required.");
2395
        }
2396 47063
        if (count($foreignKey->getForeignColumns()) === 0) {
2397
            throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
2398
        }
2399 47063
        if (strlen($foreignKey->getForeignTableName()) === 0) {
2400
            throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
2401
        }
2402
2403 47063
        return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this))
2404 47063
            . ') REFERENCES '
2405 47063
            . $foreignKey->getQuotedForeignTableName($this) . ' ('
2406 47063
            . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')';
2407
    }
2408
2409
    /**
2410
     * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
2411
     * of a field declaration to be used in statements like CREATE TABLE.
2412
     *
2413
     * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
2414
     *                of a field declaration.
2415
     */
2416
    public function getUniqueFieldDeclarationSQL()
2417
    {
2418
        return 'UNIQUE';
2419
    }
2420
2421
    /**
2422
     * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
2423
     * of a field declaration to be used in statements like CREATE TABLE.
2424
     *
2425
     * @param string $charset The name of the charset.
2426
     *
2427
     * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
2428
     *                of a field declaration.
2429
     */
2430
    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

2430
    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...
2431
    {
2432
        return '';
2433
    }
2434
2435
    /**
2436
     * Obtains DBMS specific SQL code portion needed to set the COLLATION
2437
     * of a field declaration to be used in statements like CREATE TABLE.
2438
     *
2439
     * @param string $collation The name of the collation.
2440
     *
2441
     * @return string DBMS specific SQL code portion needed to set the COLLATION
2442
     *                of a field declaration.
2443
     */
2444 43988
    public function getColumnCollationDeclarationSQL($collation)
2445
    {
2446 43988
        return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
2447
    }
2448
2449
    /**
2450
     * Whether the platform prefers sequences for ID generation.
2451
     * Subclasses should override this method to return TRUE if they prefer sequences.
2452
     *
2453
     * @return bool
2454
     */
2455 15295
    public function prefersSequences()
2456
    {
2457 15295
        return false;
2458
    }
2459
2460
    /**
2461
     * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
2462
     * Subclasses should override this method to return TRUE if they prefer identity columns.
2463
     *
2464
     * @return bool
2465
     */
2466 34086
    public function prefersIdentityColumns()
2467
    {
2468 34086
        return false;
2469
    }
2470
2471
    /**
2472
     * Some platforms need the boolean values to be converted.
2473
     *
2474
     * The default conversion in this implementation converts to integers (false => 0, true => 1).
2475
     *
2476
     * Note: if the input is not a boolean the original input might be returned.
2477
     *
2478
     * There are two contexts when converting booleans: Literals and Prepared Statements.
2479
     * This method should handle the literal case
2480
     *
2481
     * @param mixed $item A boolean or an array of them.
2482
     *
2483
     * @return mixed A boolean database value or an array of them.
2484
     */
2485 44619
    public function convertBooleans($item)
2486
    {
2487 44619
        if (is_array($item)) {
2488
            foreach ($item as $k => $value) {
2489
                if (! is_bool($value)) {
2490
                    continue;
2491
                }
2492
2493
                $item[$k] = (int) $value;
2494
            }
2495 44619
        } elseif (is_bool($item)) {
2496 44619
            $item = (int) $item;
2497
        }
2498
2499 44619
        return $item;
2500
    }
2501
2502
    /**
2503
     * Some platforms have boolean literals that needs to be correctly converted
2504
     *
2505
     * The default conversion tries to convert value into bool "(bool)$item"
2506
     *
2507
     * @param mixed $item
2508
     *
2509
     * @return bool|null
2510
     */
2511 44059
    public function convertFromBoolean($item)
2512
    {
2513 44059
        return $item === null ? null: (bool) $item;
2514
    }
2515
2516
    /**
2517
     * This method should handle the prepared statements case. When there is no
2518
     * distinction, it's OK to use the same method.
2519
     *
2520
     * Note: if the input is not a boolean the original input might be returned.
2521
     *
2522
     * @param mixed $item A boolean or an array of them.
2523
     *
2524
     * @return mixed A boolean database value or an array of them.
2525
     */
2526 39574
    public function convertBooleansToDatabaseValue($item)
2527
    {
2528 39574
        return $this->convertBooleans($item);
2529
    }
2530
2531
    /**
2532
     * Returns the SQL specific for the platform to get the current date.
2533
     *
2534
     * @return string
2535
     */
2536 42898
    public function getCurrentDateSQL()
2537
    {
2538 42898
        return 'CURRENT_DATE';
2539
    }
2540
2541
    /**
2542
     * Returns the SQL specific for the platform to get the current time.
2543
     *
2544
     * @return string
2545
     */
2546 7952
    public function getCurrentTimeSQL()
2547
    {
2548 7952
        return 'CURRENT_TIME';
2549
    }
2550
2551
    /**
2552
     * Returns the SQL specific for the platform to get the current timestamp
2553
     *
2554
     * @return string
2555
     */
2556 43566
    public function getCurrentTimestampSQL()
2557
    {
2558 43566
        return 'CURRENT_TIMESTAMP';
2559
    }
2560
2561
    /**
2562
     * Returns the SQL for a given transaction isolation level Connection constant.
2563
     *
2564
     * @param int $level
2565
     *
2566
     * @return string
2567
     *
2568
     * @throws InvalidArgumentException
2569
     */
2570 40434
    protected function _getTransactionIsolationLevelSQL($level)
2571
    {
2572
        switch ($level) {
2573 40434
            case TransactionIsolationLevel::READ_UNCOMMITTED:
2574 40434
                return 'READ UNCOMMITTED';
2575 40434
            case TransactionIsolationLevel::READ_COMMITTED:
2576 40434
                return 'READ COMMITTED';
2577 40434
            case TransactionIsolationLevel::REPEATABLE_READ:
2578 40434
                return 'REPEATABLE READ';
2579 40434
            case TransactionIsolationLevel::SERIALIZABLE:
2580 40434
                return 'SERIALIZABLE';
2581
            default:
2582
                throw new InvalidArgumentException('Invalid isolation level:' . $level);
2583
        }
2584
    }
2585
2586
    /**
2587
     * @return string
2588
     *
2589
     * @throws DBALException If not supported on this platform.
2590
     */
2591
    public function getListDatabasesSQL()
2592
    {
2593
        throw DBALException::notSupported(__METHOD__);
2594
    }
2595
2596
    /**
2597
     * Returns the SQL statement for retrieving the namespaces defined in the database.
2598
     *
2599
     * @return string
2600
     *
2601
     * @throws DBALException If not supported on this platform.
2602
     */
2603
    public function getListNamespacesSQL()
2604
    {
2605
        throw DBALException::notSupported(__METHOD__);
2606
    }
2607
2608
    /**
2609
     * @param string $database
2610
     *
2611
     * @return string
2612
     *
2613
     * @throws DBALException If not supported on this platform.
2614
     */
2615
    public function getListSequencesSQL($database)
2616
    {
2617
        throw DBALException::notSupported(__METHOD__);
2618
    }
2619
2620
    /**
2621
     * @param string $table
2622
     *
2623
     * @return string
2624
     *
2625
     * @throws DBALException If not supported on this platform.
2626
     */
2627
    public function getListTableConstraintsSQL($table)
2628
    {
2629
        throw DBALException::notSupported(__METHOD__);
2630
    }
2631
2632
    /**
2633
     * @param string      $table
2634
     * @param string|null $database
2635
     *
2636
     * @return string
2637
     *
2638
     * @throws DBALException If not supported on this platform.
2639
     */
2640
    public function getListTableColumnsSQL($table, $database = null)
2641
    {
2642
        throw DBALException::notSupported(__METHOD__);
2643
    }
2644
2645
    /**
2646
     * @return string
2647
     *
2648
     * @throws DBALException If not supported on this platform.
2649
     */
2650
    public function getListTablesSQL()
2651
    {
2652
        throw DBALException::notSupported(__METHOD__);
2653
    }
2654
2655
    /**
2656
     * @return string
2657
     *
2658
     * @throws DBALException If not supported on this platform.
2659
     */
2660
    public function getListUsersSQL()
2661
    {
2662
        throw DBALException::notSupported(__METHOD__);
2663
    }
2664
2665
    /**
2666
     * Returns the SQL to list all views of a database or user.
2667
     *
2668
     * @param string $database
2669
     *
2670
     * @return string
2671
     *
2672
     * @throws DBALException If not supported on this platform.
2673
     */
2674
    public function getListViewsSQL($database)
2675
    {
2676
        throw DBALException::notSupported(__METHOD__);
2677
    }
2678
2679
    /**
2680
     * Returns the list of indexes for the current database.
2681
     *
2682
     * The current database parameter is optional but will always be passed
2683
     * when using the SchemaManager API and is the database the given table is in.
2684
     *
2685
     * Attention: Some platforms only support currentDatabase when they
2686
     * are connected with that database. Cross-database information schema
2687
     * requests may be impossible.
2688
     *
2689
     * @param string $table
2690
     * @param string $currentDatabase
2691
     *
2692
     * @return string
2693
     *
2694
     * @throws DBALException If not supported on this platform.
2695
     */
2696
    public function getListTableIndexesSQL($table, $currentDatabase = null)
0 ignored issues
show
Unused Code introduced by
The parameter $currentDatabase 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

2696
    public function getListTableIndexesSQL($table, /** @scrutinizer ignore-unused */ $currentDatabase = null)

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...
2697
    {
2698
        throw DBALException::notSupported(__METHOD__);
2699
    }
2700
2701
    /**
2702
     * @param string $table
2703
     *
2704
     * @return string
2705
     *
2706
     * @throws DBALException If not supported on this platform.
2707
     */
2708
    public function getListTableForeignKeysSQL($table)
2709
    {
2710
        throw DBALException::notSupported(__METHOD__);
2711
    }
2712
2713
    /**
2714
     * @param string $name
2715
     * @param string $sql
2716
     *
2717
     * @return string
2718
     *
2719
     * @throws DBALException If not supported on this platform.
2720
     */
2721
    public function getCreateViewSQL($name, $sql)
2722
    {
2723
        throw DBALException::notSupported(__METHOD__);
2724
    }
2725
2726
    /**
2727
     * @param string $name
2728
     *
2729
     * @return string
2730
     *
2731
     * @throws DBALException If not supported on this platform.
2732
     */
2733
    public function getDropViewSQL($name)
2734
    {
2735
        throw DBALException::notSupported(__METHOD__);
2736
    }
2737
2738
    /**
2739
     * Returns the SQL snippet to drop an existing sequence.
2740
     *
2741
     * @param Sequence|string $sequence
2742
     *
2743
     * @return string
2744
     *
2745
     * @throws DBALException If not supported on this platform.
2746
     */
2747
    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

2747
    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...
2748
    {
2749
        throw DBALException::notSupported(__METHOD__);
2750
    }
2751
2752
    /**
2753
     * @param string $sequenceName
2754
     *
2755
     * @return string
2756
     *
2757
     * @throws DBALException If not supported on this platform.
2758
     */
2759
    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

2759
    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...
2760
    {
2761
        throw DBALException::notSupported(__METHOD__);
2762
    }
2763
2764
    /**
2765
     * Returns the SQL to create a new database.
2766
     *
2767
     * @param string $database The name of the database that should be created.
2768
     *
2769
     * @return string
2770
     *
2771
     * @throws DBALException If not supported on this platform.
2772
     */
2773 30889
    public function getCreateDatabaseSQL($database)
2774
    {
2775 30889
        throw DBALException::notSupported(__METHOD__);
2776
    }
2777
2778
    /**
2779
     * Returns the SQL to set the transaction isolation level.
2780
     *
2781
     * @param int $level
2782
     *
2783
     * @return string
2784
     *
2785
     * @throws DBALException If not supported on this platform.
2786
     */
2787
    public function getSetTransactionIsolationSQL($level)
2788
    {
2789
        throw DBALException::notSupported(__METHOD__);
2790
    }
2791
2792
    /**
2793
     * Obtains DBMS specific SQL to be used to create datetime fields in
2794
     * statements like CREATE TABLE.
2795
     *
2796
     * @param mixed[] $fieldDeclaration
2797
     *
2798
     * @return string
2799
     *
2800
     * @throws DBALException If not supported on this platform.
2801
     */
2802
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
2803
    {
2804
        throw DBALException::notSupported(__METHOD__);
2805
    }
2806
2807
    /**
2808
     * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields.
2809
     *
2810
     * @param mixed[] $fieldDeclaration
2811
     *
2812
     * @return string
2813
     */
2814 28733
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
2815
    {
2816 28733
        return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
2817
    }
2818
2819
    /**
2820
     * Obtains DBMS specific SQL to be used to create date fields in statements
2821
     * like CREATE TABLE.
2822
     *
2823
     * @param mixed[] $fieldDeclaration
2824
     *
2825
     * @return string
2826
     *
2827
     * @throws DBALException If not supported on this platform.
2828
     */
2829
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
2830
    {
2831
        throw DBALException::notSupported(__METHOD__);
2832
    }
2833
2834
    /**
2835
     * Obtains DBMS specific SQL to be used to create time fields in statements
2836
     * like CREATE TABLE.
2837
     *
2838
     * @param mixed[] $fieldDeclaration
2839
     *
2840
     * @return string
2841
     *
2842
     * @throws DBALException If not supported on this platform.
2843
     */
2844
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
2845
    {
2846
        throw DBALException::notSupported(__METHOD__);
2847
    }
2848
2849
    /**
2850
     * @param mixed[] $fieldDeclaration
2851
     *
2852
     * @return string
2853
     */
2854 42506
    public function getFloatDeclarationSQL(array $fieldDeclaration)
2855
    {
2856 42506
        return 'DOUBLE PRECISION';
2857
    }
2858
2859
    /**
2860
     * Gets the default transaction isolation level of the platform.
2861
     *
2862
     * @see TransactionIsolationLevel
2863
     *
2864
     * @return int The default isolation level.
2865
     */
2866
    public function getDefaultTransactionIsolationLevel()
2867
    {
2868
        return TransactionIsolationLevel::READ_COMMITTED;
2869
    }
2870
2871
    /* supports*() methods */
2872
2873
    /**
2874
     * Whether the platform supports sequences.
2875
     *
2876
     * @return bool
2877
     */
2878 31126
    public function supportsSequences()
2879
    {
2880 31126
        return false;
2881
    }
2882
2883
    /**
2884
     * Whether the platform supports identity columns.
2885
     *
2886
     * Identity columns are columns that receive an auto-generated value from the
2887
     * database on insert of a row.
2888
     *
2889
     * @return bool
2890
     */
2891 30751
    public function supportsIdentityColumns()
2892
    {
2893 30751
        return false;
2894
    }
2895
2896
    /**
2897
     * Whether the platform emulates identity columns through sequences.
2898
     *
2899
     * Some platforms that do not support identity columns natively
2900
     * but support sequences can emulate identity columns by using
2901
     * sequences.
2902
     *
2903
     * @return bool
2904
     */
2905 42826
    public function usesSequenceEmulatedIdentityColumns()
2906
    {
2907 42826
        return false;
2908
    }
2909
2910
    /**
2911
     * Gets the sequence name prefix based on table information.
2912
     *
2913
     * @param string      $tableName
2914
     * @param string|null $schemaName
2915
     *
2916
     * @return string
2917
     */
2918
    public function getSequencePrefix($tableName, $schemaName = null)
2919
    {
2920
        if (! $schemaName) {
2921
            return $tableName;
2922
        }
2923
2924
        // Prepend the schema name to the table name if there is one
2925
        return ! $this->supportsSchemas() && $this->canEmulateSchemas()
2926
            ? $schemaName . '__' . $tableName
2927
            : $schemaName . '.' . $tableName;
2928
    }
2929
2930
    /**
2931
     * Returns the name of the sequence for a particular identity column in a particular table.
2932
     *
2933
     * @see    usesSequenceEmulatedIdentityColumns
2934
     *
2935
     * @param string $tableName  The name of the table to return the sequence name for.
2936
     * @param string $columnName The name of the identity column in the table to return the sequence name for.
2937
     *
2938
     * @return string
2939
     *
2940
     * @throws DBALException If not supported on this platform.
2941
     */
2942 41239
    public function getIdentitySequenceName($tableName, $columnName)
2943
    {
2944 41239
        throw DBALException::notSupported(__METHOD__);
2945
    }
2946
2947
    /**
2948
     * Whether the platform supports indexes.
2949
     *
2950
     * @return bool
2951
     */
2952 15180
    public function supportsIndexes()
2953
    {
2954 15180
        return true;
2955
    }
2956
2957
    /**
2958
     * Whether the platform supports partial indexes.
2959
     *
2960
     * @return bool
2961
     */
2962 46037
    public function supportsPartialIndexes()
2963
    {
2964 46037
        return false;
2965
    }
2966
2967
    /**
2968
     * Whether the platform supports indexes with column length definitions.
2969
     */
2970 45449
    public function supportsColumnLengthIndexes() : bool
2971
    {
2972 45449
        return false;
2973
    }
2974
2975
    /**
2976
     * Whether the platform supports altering tables.
2977
     *
2978
     * @return bool
2979
     */
2980 45345
    public function supportsAlterTable()
2981
    {
2982 45345
        return true;
2983
    }
2984
2985
    /**
2986
     * Whether the platform supports transactions.
2987
     *
2988
     * @return bool
2989
     */
2990 15203
    public function supportsTransactions()
2991
    {
2992 15203
        return true;
2993
    }
2994
2995
    /**
2996
     * Whether the platform supports savepoints.
2997
     *
2998
     * @return bool
2999
     */
3000 48641
    public function supportsSavepoints()
3001
    {
3002 48641
        return true;
3003
    }
3004
3005
    /**
3006
     * Whether the platform supports releasing savepoints.
3007
     *
3008
     * @return bool
3009
     */
3010 44718
    public function supportsReleaseSavepoints()
3011
    {
3012 44718
        return $this->supportsSavepoints();
3013
    }
3014
3015
    /**
3016
     * Whether the platform supports primary key constraints.
3017
     *
3018
     * @return bool
3019
     */
3020 15272
    public function supportsPrimaryConstraints()
3021
    {
3022 15272
        return true;
3023
    }
3024
3025
    /**
3026
     * Whether the platform supports foreign key constraints.
3027
     *
3028
     * @return bool
3029
     */
3030 47114
    public function supportsForeignKeyConstraints()
3031
    {
3032 47114
        return true;
3033
    }
3034
3035
    /**
3036
     * Whether this platform supports onUpdate in foreign key constraints.
3037
     *
3038
     * @return bool
3039
     */
3040 47063
    public function supportsForeignKeyOnUpdate()
3041
    {
3042 47063
        return $this->supportsForeignKeyConstraints();
3043
    }
3044
3045
    /**
3046
     * Whether the platform supports database schemas.
3047
     *
3048
     * @return bool
3049
     */
3050 35750
    public function supportsSchemas()
3051
    {
3052 35750
        return false;
3053
    }
3054
3055
    /**
3056
     * Whether this platform can emulate schemas.
3057
     *
3058
     * Platforms that either support or emulate schemas don't automatically
3059
     * filter a schema for the namespaced elements in {@link
3060
     * AbstractManager#createSchema}.
3061
     *
3062
     * @return bool
3063
     */
3064 15019
    public function canEmulateSchemas()
3065
    {
3066 15019
        return false;
3067
    }
3068
3069
    /**
3070
     * Returns the default schema name.
3071
     *
3072
     * @return string
3073
     *
3074
     * @throws DBALException If not supported on this platform.
3075
     */
3076
    public function getDefaultSchemaName()
3077
    {
3078
        throw DBALException::notSupported(__METHOD__);
3079
    }
3080
3081
    /**
3082
     * Whether this platform supports create database.
3083
     *
3084
     * Some databases don't allow to create and drop databases at all or only with certain tools.
3085
     *
3086
     * @return bool
3087
     */
3088 45129
    public function supportsCreateDropDatabase()
3089
    {
3090 45129
        return true;
3091
    }
3092
3093
    /**
3094
     * Whether the platform supports getting the affected rows of a recent update/delete type query.
3095
     *
3096
     * @return bool
3097
     */
3098 15088
    public function supportsGettingAffectedRows()
3099
    {
3100 15088
        return true;
3101
    }
3102
3103
    /**
3104
     * Whether this platform support to add inline column comments as postfix.
3105
     *
3106
     * @return bool
3107
     */
3108 45227
    public function supportsInlineColumnComments()
3109
    {
3110 45227
        return false;
3111
    }
3112
3113
    /**
3114
     * Whether this platform support the proprietary syntax "COMMENT ON asset".
3115
     *
3116
     * @return bool
3117
     */
3118 46482
    public function supportsCommentOnStatement()
3119
    {
3120 46482
        return false;
3121
    }
3122
3123
    /**
3124
     * Does this platform have native guid type.
3125
     *
3126
     * @return bool
3127
     */
3128 47149
    public function hasNativeGuidType()
3129
    {
3130 47149
        return false;
3131
    }
3132
3133
    /**
3134
     * Does this platform have native JSON type.
3135
     *
3136
     * @return bool
3137
     */
3138 46495
    public function hasNativeJsonType()
3139
    {
3140 46495
        return false;
3141
    }
3142
3143
    /**
3144
     * Whether this platform supports views.
3145
     *
3146
     * @return bool
3147
     */
3148 45314
    public function supportsViews()
3149
    {
3150 45314
        return true;
3151
    }
3152
3153
    /**
3154
     * Does this platform support column collation?
3155
     *
3156
     * @return bool
3157
     */
3158
    public function supportsColumnCollation()
3159
    {
3160
        return false;
3161
    }
3162
3163
    /**
3164
     * Gets the format string, as accepted by the date() function, that describes
3165
     * the format of a stored datetime value of this platform.
3166
     *
3167
     * @return string The format string.
3168
     */
3169 44741
    public function getDateTimeFormatString()
3170
    {
3171 44741
        return 'Y-m-d H:i:s';
3172
    }
3173
3174
    /**
3175
     * Gets the format string, as accepted by the date() function, that describes
3176
     * the format of a stored datetime with timezone value of this platform.
3177
     *
3178
     * @return string The format string.
3179
     */
3180 28943
    public function getDateTimeTzFormatString()
3181
    {
3182 28943
        return 'Y-m-d H:i:s';
3183
    }
3184
3185
    /**
3186
     * Gets the format string, as accepted by the date() function, that describes
3187
     * the format of a stored date value of this platform.
3188
     *
3189
     * @return string The format string.
3190
     */
3191 40087
    public function getDateFormatString()
3192
    {
3193 40087
        return 'Y-m-d';
3194
    }
3195
3196
    /**
3197
     * Gets the format string, as accepted by the date() function, that describes
3198
     * the format of a stored time value of this platform.
3199
     *
3200
     * @return string The format string.
3201
     */
3202 39968
    public function getTimeFormatString()
3203
    {
3204 39968
        return 'H:i:s';
3205
    }
3206
3207
    /**
3208
     * Adds an driver-specific LIMIT clause to the query.
3209
     *
3210
     * @throws DBALException
3211
     */
3212 46829
    final public function modifyLimitQuery(string $query, ?int $limit, int $offset = 0) : string
3213
    {
3214 46829
        if ($offset < 0) {
3215
            throw new DBALException(sprintf(
3216
                'Offset must be a positive integer or zero, %d given',
3217
                $offset
3218
            ));
3219
        }
3220
3221 46829
        if ($offset > 0 && ! $this->supportsLimitOffset()) {
3222
            throw new DBALException(sprintf(
3223
                'Platform %s does not support offset values in limit queries.',
3224
                $this->getName()
3225
            ));
3226
        }
3227
3228 46829
        return $this->doModifyLimitQuery($query, $limit, $offset);
3229
    }
3230
3231
    /**
3232
     * Adds an platform-specific LIMIT clause to the query.
3233
     */
3234 32522
    protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string
3235
    {
3236 32522
        if ($limit !== null) {
3237 32522
            $query .= sprintf(' LIMIT %d', $limit);
3238
        }
3239
3240 32522
        if ($offset > 0) {
3241 16032
            $query .= sprintf(' OFFSET %d', $offset);
3242
        }
3243
3244 32522
        return $query;
3245
    }
3246
3247
    /**
3248
     * Whether the database platform support offsets in modify limit clauses.
3249
     *
3250
     * @return bool
3251
     */
3252 46529
    public function supportsLimitOffset()
3253
    {
3254 46529
        return true;
3255
    }
3256
3257
    /**
3258
     * Gets the character casing of a column in an SQL result set of this platform.
3259
     *
3260
     * @param string $column The column name for which to get the correct character casing.
3261
     *
3262
     * @return string The column name in the character casing used in SQL result sets.
3263
     */
3264
    public function getSQLResultCasing($column)
3265
    {
3266
        return $column;
3267
    }
3268
3269
    /**
3270
     * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
3271
     * by restrictions of the platform, like a maximum length.
3272
     *
3273
     * @param string $schemaElementName
3274
     *
3275
     * @return string
3276
     */
3277
    public function fixSchemaElementName($schemaElementName)
3278
    {
3279
        return $schemaElementName;
3280
    }
3281
3282
    /**
3283
     * Maximum length of any given database identifier, like tables or column names.
3284
     *
3285
     * @return int
3286
     */
3287 46456
    public function getMaxIdentifierLength()
3288
    {
3289 46456
        return 63;
3290
    }
3291
3292
    /**
3293
     * Returns the insert SQL for an empty insert statement.
3294
     *
3295
     * @param string $tableName
3296
     * @param string $identifierColumnName
3297
     *
3298
     * @return string
3299
     */
3300 26404
    public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
3301
    {
3302 26404
        return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
3303
    }
3304
3305
    /**
3306
     * Generates a Truncate Table SQL statement for a given table.
3307
     *
3308
     * Cascade is not supported on many platforms but would optionally cascade the truncate by
3309
     * following the foreign keys.
3310
     *
3311
     * @param string $tableName
3312
     * @param bool   $cascade
3313
     *
3314
     * @return string
3315
     */
3316 43761
    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

3316
    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...
3317
    {
3318 43761
        $tableIdentifier = new Identifier($tableName);
3319
3320 43761
        return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
3321
    }
3322
3323
    /**
3324
     * This is for test reasons, many vendors have special requirements for dummy statements.
3325
     */
3326 46844
    public function getDummySelectSQL(string $expression = '1') : string
3327
    {
3328 46844
        return sprintf('SELECT %s', $expression);
3329
    }
3330
3331
    /**
3332
     * Returns the SQL to create a new savepoint.
3333
     *
3334
     * @param string $savepoint
3335
     *
3336
     * @return string
3337
     */
3338 42744
    public function createSavePoint($savepoint)
3339
    {
3340 42744
        return 'SAVEPOINT ' . $savepoint;
3341
    }
3342
3343
    /**
3344
     * Returns the SQL to release a savepoint.
3345
     *
3346
     * @param string $savepoint
3347
     *
3348
     * @return string
3349
     */
3350 42744
    public function releaseSavePoint($savepoint)
3351
    {
3352 42744
        return 'RELEASE SAVEPOINT ' . $savepoint;
3353
    }
3354
3355
    /**
3356
     * Returns the SQL to rollback a savepoint.
3357
     *
3358
     * @param string $savepoint
3359
     *
3360
     * @return string
3361
     */
3362 42744
    public function rollbackSavePoint($savepoint)
3363
    {
3364 42744
        return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
3365
    }
3366
3367
    /**
3368
     * Returns the keyword list instance of this platform.
3369
     *
3370
     * @return KeywordList
3371
     *
3372
     * @throws DBALException If no keyword list is specified.
3373
     */
3374 49107
    final public function getReservedKeywordsList()
3375
    {
3376
        // Check for an existing instantiation of the keywords class.
3377 49107
        if ($this->_keywords) {
3378 49107
            return $this->_keywords;
3379
        }
3380
3381 49107
        $class    = $this->getReservedKeywordsClass();
3382 49107
        $keywords = new $class();
3383 49107
        if (! $keywords instanceof KeywordList) {
3384
            throw DBALException::notSupported(__METHOD__);
3385
        }
3386
3387
        // Store the instance so it doesn't need to be generated on every request.
3388 49107
        $this->_keywords = $keywords;
3389
3390 49107
        return $keywords;
3391
    }
3392
3393
    /**
3394
     * Returns the class name of the reserved keywords list.
3395
     *
3396
     * @return string
3397
     *
3398
     * @throws DBALException If not supported on this platform.
3399
     */
3400
    protected function getReservedKeywordsClass()
3401
    {
3402
        throw DBALException::notSupported(__METHOD__);
3403
    }
3404
3405
    /**
3406
     * Quotes a literal string.
3407
     * This method is NOT meant to fix SQL injections!
3408
     * It is only meant to escape this platform's string literal
3409
     * quote character inside the given literal string.
3410
     *
3411
     * @param string $str The literal string to be quoted.
3412
     *
3413
     * @return string The quoted literal string.
3414
     */
3415 46578
    public function quoteStringLiteral($str)
3416
    {
3417 46578
        $c = $this->getStringLiteralQuoteCharacter();
3418
3419 46578
        return $c . str_replace($c, $c . $c, $str) . $c;
3420
    }
3421
3422
    /**
3423
     * Gets the character used for string literal quoting.
3424
     *
3425
     * @return string
3426
     */
3427 46578
    public function getStringLiteralQuoteCharacter()
3428
    {
3429 46578
        return "'";
3430
    }
3431
3432
    /**
3433
     * Escapes metacharacters in a string intended to be used with a LIKE
3434
     * operator.
3435
     *
3436
     * @param string $inputString a literal, unquoted string
3437
     * @param string $escapeChar  should be reused by the caller in the LIKE
3438
     *                            expression.
3439
     */
3440 47022
    final public function escapeStringForLike(string $inputString, string $escapeChar) : string
3441
    {
3442 47022
        return preg_replace(
3443 47022
            '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u',
3444 47022
            addcslashes($escapeChar, '\\') . '$1',
3445 47022
            $inputString
3446
        );
3447
    }
3448
3449 47022
    protected function getLikeWildcardCharacters() : string
3450
    {
3451 47022
        return '%_';
3452
    }
3453
}
3454