summaryrefslogtreecommitdiff
path: root/vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php')
-rw-r--r--vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php784
1 files changed, 784 insertions, 0 deletions
diff --git a/vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php b/vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php
new file mode 100644
index 0000000..166ee75
--- /dev/null
+++ b/vendor/doctrine/dbal/src/Platforms/PostgreSQLPlatform.php
@@ -0,0 +1,784 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\DBAL\Platforms;
6
7use Doctrine\DBAL\Connection;
8use Doctrine\DBAL\Platforms\Keywords\KeywordList;
9use Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords;
10use Doctrine\DBAL\Schema\ForeignKeyConstraint;
11use Doctrine\DBAL\Schema\Identifier;
12use Doctrine\DBAL\Schema\Index;
13use Doctrine\DBAL\Schema\PostgreSQLSchemaManager;
14use Doctrine\DBAL\Schema\Sequence;
15use Doctrine\DBAL\Schema\TableDiff;
16use Doctrine\DBAL\TransactionIsolationLevel;
17use Doctrine\DBAL\Types\Types;
18use UnexpectedValueException;
19
20use function array_merge;
21use function array_unique;
22use function array_values;
23use function explode;
24use function implode;
25use function in_array;
26use function is_array;
27use function is_bool;
28use function is_numeric;
29use function is_string;
30use function sprintf;
31use function str_contains;
32use function strtolower;
33use function trim;
34
35/**
36 * Provides the behavior, features and SQL dialect of the PostgreSQL 9.4+ database platform.
37 */
38class PostgreSQLPlatform extends AbstractPlatform
39{
40 private bool $useBooleanTrueFalseStrings = true;
41
42 /** @var string[][] PostgreSQL booleans literals */
43 private array $booleanLiterals = [
44 'true' => [
45 't',
46 'true',
47 'y',
48 'yes',
49 'on',
50 '1',
51 ],
52 'false' => [
53 'f',
54 'false',
55 'n',
56 'no',
57 'off',
58 '0',
59 ],
60 ];
61
62 /**
63 * PostgreSQL has different behavior with some drivers
64 * with regard to how booleans have to be handled.
65 *
66 * Enables use of 'true'/'false' or otherwise 1 and 0 instead.
67 */
68 public function setUseBooleanTrueFalseStrings(bool $flag): void
69 {
70 $this->useBooleanTrueFalseStrings = $flag;
71 }
72
73 public function getRegexpExpression(): string
74 {
75 return 'SIMILAR TO';
76 }
77
78 public function getLocateExpression(string $string, string $substring, ?string $start = null): string
79 {
80 if ($start !== null) {
81 $string = $this->getSubstringExpression($string, $start);
82
83 return 'CASE WHEN (POSITION(' . $substring . ' IN ' . $string . ') = 0) THEN 0'
84 . ' ELSE (POSITION(' . $substring . ' IN ' . $string . ') + ' . $start . ' - 1) END';
85 }
86
87 return sprintf('POSITION(%s IN %s)', $substring, $string);
88 }
89
90 protected function getDateArithmeticIntervalExpression(
91 string $date,
92 string $operator,
93 string $interval,
94 DateIntervalUnit $unit,
95 ): string {
96 if ($unit === DateIntervalUnit::QUARTER) {
97 $interval = $this->multiplyInterval($interval, 3);
98 $unit = DateIntervalUnit::MONTH;
99 }
100
101 return '(' . $date . ' ' . $operator . ' (' . $interval . " || ' " . $unit->value . "')::interval)";
102 }
103
104 public function getDateDiffExpression(string $date1, string $date2): string
105 {
106 return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))';
107 }
108
109 public function getCurrentDatabaseExpression(): string
110 {
111 return 'CURRENT_DATABASE()';
112 }
113
114 public function supportsSequences(): bool
115 {
116 return true;
117 }
118
119 public function supportsSchemas(): bool
120 {
121 return true;
122 }
123
124 public function supportsIdentityColumns(): bool
125 {
126 return true;
127 }
128
129 /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */
130 public function supportsPartialIndexes(): bool
131 {
132 return true;
133 }
134
135 /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */
136 public function supportsCommentOnStatement(): bool
137 {
138 return true;
139 }
140
141 /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */
142 public function getListDatabasesSQL(): string
143 {
144 return 'SELECT datname FROM pg_database';
145 }
146
147 /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */
148 public function getListSequencesSQL(string $database): string
149 {
150 return 'SELECT sequence_name AS relname,
151 sequence_schema AS schemaname,
152 minimum_value AS min_value,
153 increment AS increment_by
154 FROM information_schema.sequences
155 WHERE sequence_catalog = ' . $this->quoteStringLiteral($database) . "
156 AND sequence_schema NOT LIKE 'pg\_%'
157 AND sequence_schema != 'information_schema'";
158 }
159
160 /** @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy. */
161 public function getListViewsSQL(string $database): string
162 {
163 return 'SELECT quote_ident(table_name) AS viewname,
164 table_schema AS schemaname,
165 view_definition AS definition
166 FROM information_schema.views
167 WHERE view_definition IS NOT NULL';
168 }
169
170 /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */
171 public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey): string
172 {
173 $query = '';
174
175 if ($foreignKey->hasOption('match')) {
176 $query .= ' MATCH ' . $foreignKey->getOption('match');
177 }
178
179 $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
180
181 if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
182 $query .= ' DEFERRABLE';
183 } else {
184 $query .= ' NOT DEFERRABLE';
185 }
186
187 if (
188 $foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false
189 ) {
190 $query .= ' INITIALLY DEFERRED';
191 } else {
192 $query .= ' INITIALLY IMMEDIATE';
193 }
194
195 return $query;
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 public function getAlterTableSQL(TableDiff $diff): array
202 {
203 $sql = [];
204 $commentsSQL = [];
205 $columnSql = [];
206
207 $table = $diff->getOldTable();
208
209 $tableNameSQL = $table->getQuotedName($this);
210
211 foreach ($diff->getAddedColumns() as $addedColumn) {
212 $query = 'ADD ' . $this->getColumnDeclarationSQL(
213 $addedColumn->getQuotedName($this),
214 $addedColumn->toArray(),
215 );
216
217 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
218
219 $comment = $addedColumn->getComment();
220
221 if ($comment === '') {
222 continue;
223 }
224
225 $commentsSQL[] = $this->getCommentOnColumnSQL(
226 $tableNameSQL,
227 $addedColumn->getQuotedName($this),
228 $comment,
229 );
230 }
231
232 foreach ($diff->getDroppedColumns() as $droppedColumn) {
233 $query = 'DROP ' . $droppedColumn->getQuotedName($this);
234 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
235 }
236
237 foreach ($diff->getModifiedColumns() as $columnDiff) {
238 $oldColumn = $columnDiff->getOldColumn();
239 $newColumn = $columnDiff->getNewColumn();
240
241 $oldColumnName = $oldColumn->getQuotedName($this);
242
243 if (
244 $columnDiff->hasTypeChanged()
245 || $columnDiff->hasPrecisionChanged()
246 || $columnDiff->hasScaleChanged()
247 || $columnDiff->hasFixedChanged()
248 ) {
249 $type = $newColumn->getType();
250
251 // SERIAL/BIGSERIAL are not "real" types and we can't alter a column to that type
252 $columnDefinition = $newColumn->toArray();
253 $columnDefinition['autoincrement'] = false;
254
255 // here was a server version check before, but DBAL API does not support this anymore.
256 $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this);
257 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
258 }
259
260 if ($columnDiff->hasDefaultChanged()) {
261 $defaultClause = $newColumn->getDefault() === null
262 ? ' DROP DEFAULT'
263 : ' SET' . $this->getDefaultValueDeclarationSQL($newColumn->toArray());
264
265 $query = 'ALTER ' . $oldColumnName . $defaultClause;
266 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
267 }
268
269 if ($columnDiff->hasNotNullChanged()) {
270 $query = 'ALTER ' . $oldColumnName . ' ' . ($newColumn->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL';
271 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
272 }
273
274 if ($columnDiff->hasAutoIncrementChanged()) {
275 if ($newColumn->getAutoincrement()) {
276 $query = 'ADD GENERATED BY DEFAULT AS IDENTITY';
277 } else {
278 $query = 'DROP IDENTITY';
279 }
280
281 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ALTER ' . $oldColumnName . ' ' . $query;
282 }
283
284 $newComment = $newColumn->getComment();
285 $oldComment = $columnDiff->getOldColumn()->getComment();
286
287 if ($columnDiff->hasCommentChanged() || $oldComment !== $newComment) {
288 $commentsSQL[] = $this->getCommentOnColumnSQL(
289 $tableNameSQL,
290 $newColumn->getQuotedName($this),
291 $newComment,
292 );
293 }
294
295 if (! $columnDiff->hasLengthChanged()) {
296 continue;
297 }
298
299 $query = 'ALTER ' . $oldColumnName . ' TYPE '
300 . $newColumn->getType()->getSQLDeclaration($newColumn->toArray(), $this);
301 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' ' . $query;
302 }
303
304 foreach ($diff->getRenamedColumns() as $oldColumnName => $column) {
305 $oldColumnName = new Identifier($oldColumnName);
306
307 $sql[] = 'ALTER TABLE ' . $tableNameSQL . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this)
308 . ' TO ' . $column->getQuotedName($this);
309 }
310
311 return array_merge(
312 $this->getPreAlterTableIndexForeignKeySQL($diff),
313 $sql,
314 $commentsSQL,
315 $this->getPostAlterTableIndexForeignKeySQL($diff),
316 $columnSql,
317 );
318 }
319
320 /**
321 * {@inheritDoc}
322 */
323 protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName): array
324 {
325 if (str_contains($tableName, '.')) {
326 [$schema] = explode('.', $tableName);
327 $oldIndexName = $schema . '.' . $oldIndexName;
328 }
329
330 return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)];
331 }
332
333 public function getCreateSequenceSQL(Sequence $sequence): string
334 {
335 return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
336 ' INCREMENT BY ' . $sequence->getAllocationSize() .
337 ' MINVALUE ' . $sequence->getInitialValue() .
338 ' START ' . $sequence->getInitialValue() .
339 $this->getSequenceCacheSQL($sequence);
340 }
341
342 public function getAlterSequenceSQL(Sequence $sequence): string
343 {
344 return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) .
345 ' INCREMENT BY ' . $sequence->getAllocationSize() .
346 $this->getSequenceCacheSQL($sequence);
347 }
348
349 /**
350 * Cache definition for sequences
351 */
352 private function getSequenceCacheSQL(Sequence $sequence): string
353 {
354 if ($sequence->getCache() > 1) {
355 return ' CACHE ' . $sequence->getCache();
356 }
357
358 return '';
359 }
360
361 public function getDropSequenceSQL(string $name): string
362 {
363 return parent::getDropSequenceSQL($name) . ' CASCADE';
364 }
365
366 public function getDropForeignKeySQL(string $foreignKey, string $table): string
367 {
368 return $this->getDropConstraintSQL($foreignKey, $table);
369 }
370
371 public function getDropIndexSQL(string $name, string $table): string
372 {
373 if ($name === '"primary"') {
374 $constraintName = $table . '_pkey';
375
376 return $this->getDropConstraintSQL($constraintName, $table);
377 }
378
379 return parent::getDropIndexSQL($name, $table);
380 }
381
382 /**
383 * {@inheritDoc}
384 */
385 protected function _getCreateTableSQL(string $name, array $columns, array $options = []): array
386 {
387 $queryFields = $this->getColumnDeclarationListSQL($columns);
388
389 if (isset($options['primary']) && ! empty($options['primary'])) {
390 $keyColumns = array_unique(array_values($options['primary']));
391 $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
392 }
393
394 $unlogged = isset($options['unlogged']) && $options['unlogged'] === true ? ' UNLOGGED' : '';
395
396 $query = 'CREATE' . $unlogged . ' TABLE ' . $name . ' (' . $queryFields . ')';
397
398 $sql = [$query];
399
400 if (isset($options['indexes']) && ! empty($options['indexes'])) {
401 foreach ($options['indexes'] as $index) {
402 $sql[] = $this->getCreateIndexSQL($index, $name);
403 }
404 }
405
406 if (isset($options['uniqueConstraints'])) {
407 foreach ($options['uniqueConstraints'] as $uniqueConstraint) {
408 $sql[] = $this->getCreateUniqueConstraintSQL($uniqueConstraint, $name);
409 }
410 }
411
412 if (isset($options['foreignKeys'])) {
413 foreach ($options['foreignKeys'] as $definition) {
414 $sql[] = $this->getCreateForeignKeySQL($definition, $name);
415 }
416 }
417
418 return $sql;
419 }
420
421 /**
422 * Converts a single boolean value.
423 *
424 * First converts the value to its native PHP boolean type
425 * and passes it to the given callback function to be reconverted
426 * into any custom representation.
427 *
428 * @param mixed $value The value to convert.
429 * @param callable $callback The callback function to use for converting the real boolean value.
430 *
431 * @throws UnexpectedValueException
432 */
433 private function convertSingleBooleanValue(mixed $value, callable $callback): mixed
434 {
435 if ($value === null) {
436 return $callback(null);
437 }
438
439 if (is_bool($value) || is_numeric($value)) {
440 return $callback((bool) $value);
441 }
442
443 if (! is_string($value)) {
444 return $callback(true);
445 }
446
447 /**
448 * Better safe than sorry: http://php.net/in_array#106319
449 */
450 if (in_array(strtolower(trim($value)), $this->booleanLiterals['false'], true)) {
451 return $callback(false);
452 }
453
454 if (in_array(strtolower(trim($value)), $this->booleanLiterals['true'], true)) {
455 return $callback(true);
456 }
457
458 throw new UnexpectedValueException(sprintf(
459 'Unrecognized boolean literal, %s given.',
460 $value,
461 ));
462 }
463
464 /**
465 * Converts one or multiple boolean values.
466 *
467 * First converts the value(s) to their native PHP boolean type
468 * and passes them to the given callback function to be reconverted
469 * into any custom representation.
470 *
471 * @param mixed $item The value(s) to convert.
472 * @param callable $callback The callback function to use for converting the real boolean value(s).
473 */
474 private function doConvertBooleans(mixed $item, callable $callback): mixed
475 {
476 if (is_array($item)) {
477 foreach ($item as $key => $value) {
478 $item[$key] = $this->convertSingleBooleanValue($value, $callback);
479 }
480
481 return $item;
482 }
483
484 return $this->convertSingleBooleanValue($item, $callback);
485 }
486
487 /**
488 * {@inheritDoc}
489 *
490 * Postgres wants boolean values converted to the strings 'true'/'false'.
491 */
492 public function convertBooleans(mixed $item): mixed
493 {
494 if (! $this->useBooleanTrueFalseStrings) {
495 return parent::convertBooleans($item);
496 }
497
498 return $this->doConvertBooleans(
499 $item,
500 /** @param mixed $value */
501 static function ($value): string {
502 if ($value === null) {
503 return 'NULL';
504 }
505
506 return $value === true ? 'true' : 'false';
507 },
508 );
509 }
510
511 public function convertBooleansToDatabaseValue(mixed $item): mixed
512 {
513 if (! $this->useBooleanTrueFalseStrings) {
514 return parent::convertBooleansToDatabaseValue($item);
515 }
516
517 return $this->doConvertBooleans(
518 $item,
519 /** @param mixed $value */
520 static function ($value): ?int {
521 return $value === null ? null : (int) $value;
522 },
523 );
524 }
525
526 /**
527 * @param T $item
528 *
529 * @return (T is null ? null : bool)
530 *
531 * @template T
532 */
533 public function convertFromBoolean(mixed $item): ?bool
534 {
535 if (in_array($item, $this->booleanLiterals['false'], true)) {
536 return false;
537 }
538
539 return parent::convertFromBoolean($item);
540 }
541
542 public function getSequenceNextValSQL(string $sequence): string
543 {
544 return "SELECT NEXTVAL('" . $sequence . "')";
545 }
546
547 public function getSetTransactionIsolationSQL(TransactionIsolationLevel $level): string
548 {
549 return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
550 . $this->_getTransactionIsolationLevelSQL($level);
551 }
552
553 /**
554 * {@inheritDoc}
555 */
556 public function getBooleanTypeDeclarationSQL(array $column): string
557 {
558 return 'BOOLEAN';
559 }
560
561 /**
562 * {@inheritDoc}
563 */
564 public function getIntegerTypeDeclarationSQL(array $column): string
565 {
566 return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($column);
567 }
568
569 /**
570 * {@inheritDoc}
571 */
572 public function getBigIntTypeDeclarationSQL(array $column): string
573 {
574 return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column);
575 }
576
577 /**
578 * {@inheritDoc}
579 */
580 public function getSmallIntTypeDeclarationSQL(array $column): string
581 {
582 return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($column);
583 }
584
585 /**
586 * {@inheritDoc}
587 */
588 public function getGuidTypeDeclarationSQL(array $column): string
589 {
590 return 'UUID';
591 }
592
593 /**
594 * {@inheritDoc}
595 */
596 public function getDateTimeTypeDeclarationSQL(array $column): string
597 {
598 return 'TIMESTAMP(0) WITHOUT TIME ZONE';
599 }
600
601 /**
602 * {@inheritDoc}
603 */
604 public function getDateTimeTzTypeDeclarationSQL(array $column): string
605 {
606 return 'TIMESTAMP(0) WITH TIME ZONE';
607 }
608
609 /**
610 * {@inheritDoc}
611 */
612 public function getDateTypeDeclarationSQL(array $column): string
613 {
614 return 'DATE';
615 }
616
617 /**
618 * {@inheritDoc}
619 */
620 public function getTimeTypeDeclarationSQL(array $column): string
621 {
622 return 'TIME(0) WITHOUT TIME ZONE';
623 }
624
625 /**
626 * {@inheritDoc}
627 */
628 protected function _getCommonIntegerTypeDeclarationSQL(array $column): string
629 {
630 if (! empty($column['autoincrement'])) {
631 return ' GENERATED BY DEFAULT AS IDENTITY';
632 }
633
634 return '';
635 }
636
637 protected function getVarcharTypeDeclarationSQLSnippet(?int $length): string
638 {
639 $sql = 'VARCHAR';
640
641 if ($length !== null) {
642 $sql .= sprintf('(%d)', $length);
643 }
644
645 return $sql;
646 }
647
648 protected function getBinaryTypeDeclarationSQLSnippet(?int $length): string
649 {
650 return 'BYTEA';
651 }
652
653 protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length): string
654 {
655 return 'BYTEA';
656 }
657
658 /**
659 * {@inheritDoc}
660 */
661 public function getClobTypeDeclarationSQL(array $column): string
662 {
663 return 'TEXT';
664 }
665
666 public function getDateTimeTzFormatString(): string
667 {
668 return 'Y-m-d H:i:sO';
669 }
670
671 public function getEmptyIdentityInsertSQL(string $quotedTableName, string $quotedIdentifierColumnName): string
672 {
673 return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
674 }
675
676 public function getTruncateTableSQL(string $tableName, bool $cascade = false): string
677 {
678 $tableIdentifier = new Identifier($tableName);
679 $sql = 'TRUNCATE ' . $tableIdentifier->getQuotedName($this);
680
681 if ($cascade) {
682 $sql .= ' CASCADE';
683 }
684
685 return $sql;
686 }
687
688 protected function initializeDoctrineTypeMappings(): void
689 {
690 $this->doctrineTypeMapping = [
691 'bigint' => Types::BIGINT,
692 'bigserial' => Types::BIGINT,
693 'bool' => Types::BOOLEAN,
694 'boolean' => Types::BOOLEAN,
695 'bpchar' => Types::STRING,
696 'bytea' => Types::BLOB,
697 'char' => Types::STRING,
698 'date' => Types::DATE_MUTABLE,
699 'datetime' => Types::DATETIME_MUTABLE,
700 'decimal' => Types::DECIMAL,
701 'double' => Types::FLOAT,
702 'double precision' => Types::FLOAT,
703 'float' => Types::FLOAT,
704 'float4' => Types::FLOAT,
705 'float8' => Types::FLOAT,
706 'inet' => Types::STRING,
707 'int' => Types::INTEGER,
708 'int2' => Types::SMALLINT,
709 'int4' => Types::INTEGER,
710 'int8' => Types::BIGINT,
711 'integer' => Types::INTEGER,
712 'interval' => Types::STRING,
713 'json' => Types::JSON,
714 'jsonb' => Types::JSON,
715 'money' => Types::DECIMAL,
716 'numeric' => Types::DECIMAL,
717 'serial' => Types::INTEGER,
718 'serial4' => Types::INTEGER,
719 'serial8' => Types::BIGINT,
720 'real' => Types::FLOAT,
721 'smallint' => Types::SMALLINT,
722 'text' => Types::TEXT,
723 'time' => Types::TIME_MUTABLE,
724 'timestamp' => Types::DATETIME_MUTABLE,
725 'timestamptz' => Types::DATETIMETZ_MUTABLE,
726 'timetz' => Types::TIME_MUTABLE,
727 'tsvector' => Types::TEXT,
728 'uuid' => Types::GUID,
729 'varchar' => Types::STRING,
730 'year' => Types::DATE_MUTABLE,
731 '_varchar' => Types::STRING,
732 ];
733 }
734
735 protected function createReservedKeywordsList(): KeywordList
736 {
737 return new PostgreSQLKeywords();
738 }
739
740 /**
741 * {@inheritDoc}
742 */
743 public function getBlobTypeDeclarationSQL(array $column): string
744 {
745 return 'BYTEA';
746 }
747
748 /**
749 * {@inheritDoc}
750 *
751 * @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy.
752 */
753 public function getDefaultValueDeclarationSQL(array $column): string
754 {
755 if (isset($column['autoincrement']) && $column['autoincrement'] === true) {
756 return '';
757 }
758
759 return parent::getDefaultValueDeclarationSQL($column);
760 }
761
762 /** @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy. */
763 public function supportsColumnCollation(): bool
764 {
765 return true;
766 }
767
768 /**
769 * {@inheritDoc}
770 */
771 public function getJsonTypeDeclarationSQL(array $column): string
772 {
773 if (! empty($column['jsonb'])) {
774 return 'JSONB';
775 }
776
777 return 'JSON';
778 }
779
780 public function createSchemaManager(Connection $connection): PostgreSQLSchemaManager
781 {
782 return new PostgreSQLSchemaManager($connection, $this);
783 }
784}