vendor/doctrine/dbal/src/Platforms/AbstractPlatform.php line 4336

Open in your IDE?
  1. <?php
  2. namespace Doctrine\DBAL\Platforms;
  3. use Doctrine\Common\EventManager;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
  6. use Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs;
  7. use Doctrine\DBAL\Event\SchemaAlterTableEventArgs;
  8. use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
  9. use Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs;
  10. use Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs;
  11. use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
  12. use Doctrine\DBAL\Event\SchemaDropTableEventArgs;
  13. use Doctrine\DBAL\Events;
  14. use Doctrine\DBAL\Exception;
  15. use Doctrine\DBAL\Exception\InvalidLockMode;
  16. use Doctrine\DBAL\LockMode;
  17. use Doctrine\DBAL\Platforms\Keywords\KeywordList;
  18. use Doctrine\DBAL\Schema\AbstractSchemaManager;
  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\SchemaDiff;
  26. use Doctrine\DBAL\Schema\Sequence;
  27. use Doctrine\DBAL\Schema\Table;
  28. use Doctrine\DBAL\Schema\TableDiff;
  29. use Doctrine\DBAL\Schema\UniqueConstraint;
  30. use Doctrine\DBAL\SQL\Parser;
  31. use Doctrine\DBAL\TransactionIsolationLevel;
  32. use Doctrine\DBAL\Types;
  33. use Doctrine\DBAL\Types\Type;
  34. use Doctrine\Deprecations\Deprecation;
  35. use InvalidArgumentException;
  36. use UnexpectedValueException;
  37. use function addcslashes;
  38. use function array_map;
  39. use function array_merge;
  40. use function array_unique;
  41. use function array_values;
  42. use function assert;
  43. use function count;
  44. use function explode;
  45. use function func_get_arg;
  46. use function func_get_args;
  47. use function func_num_args;
  48. use function implode;
  49. use function in_array;
  50. use function is_array;
  51. use function is_bool;
  52. use function is_int;
  53. use function is_string;
  54. use function preg_quote;
  55. use function preg_replace;
  56. use function sprintf;
  57. use function str_replace;
  58. use function strlen;
  59. use function strpos;
  60. use function strtolower;
  61. use function strtoupper;
  62. /**
  63.  * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
  64.  * point of abstraction of platform-specific behaviors, features and SQL dialects.
  65.  * They are a passive source of information.
  66.  *
  67.  * @todo Remove any unnecessary methods.
  68.  */
  69. abstract class AbstractPlatform
  70. {
  71.     public const CREATE_INDEXES 1;
  72.     public const CREATE_FOREIGNKEYS 2;
  73.     /** @var string[]|null */
  74.     protected $doctrineTypeMapping;
  75.     /**
  76.      * Contains a list of all columns that should generate parseable column comments for type-detection
  77.      * in reverse engineering scenarios.
  78.      *
  79.      * @deprecated This property is deprecated and will be removed in Doctrine DBAL 4.0.
  80.      *
  81.      * @var string[]|null
  82.      */
  83.     protected $doctrineTypeComments;
  84.     /**
  85.      * @deprecated
  86.      *
  87.      * @var EventManager|null
  88.      */
  89.     protected $_eventManager;
  90.     /**
  91.      * Holds the KeywordList instance for the current platform.
  92.      *
  93.      * @var KeywordList|null
  94.      */
  95.     protected $_keywords;
  96.     private bool $disableTypeComments false;
  97.     /** @internal */
  98.     final public function setDisableTypeComments(bool $value): void
  99.     {
  100.         $this->disableTypeComments $value;
  101.     }
  102.     /**
  103.      * Sets the EventManager used by the Platform.
  104.      *
  105.      * @deprecated
  106.      *
  107.      * @return void
  108.      */
  109.     public function setEventManager(EventManager $eventManager)
  110.     {
  111.         Deprecation::triggerIfCalledFromOutside(
  112.             'doctrine/dbal',
  113.             'https://github.com/doctrine/dbal/issues/5784',
  114.             '%s is deprecated.',
  115.             __METHOD__,
  116.         );
  117.         $this->_eventManager $eventManager;
  118.     }
  119.     /**
  120.      * Gets the EventManager used by the Platform.
  121.      *
  122.      * @deprecated
  123.      *
  124.      * @return EventManager|null
  125.      */
  126.     public function getEventManager()
  127.     {
  128.         Deprecation::triggerIfCalledFromOutside(
  129.             'doctrine/dbal',
  130.             'https://github.com/doctrine/dbal/issues/5784',
  131.             '%s is deprecated.',
  132.             __METHOD__,
  133.         );
  134.         return $this->_eventManager;
  135.     }
  136.     /**
  137.      * Returns the SQL snippet that declares a boolean column.
  138.      *
  139.      * @param mixed[] $column
  140.      *
  141.      * @return string
  142.      */
  143.     abstract public function getBooleanTypeDeclarationSQL(array $column);
  144.     /**
  145.      * Returns the SQL snippet that declares a 4 byte integer column.
  146.      *
  147.      * @param mixed[] $column
  148.      *
  149.      * @return string
  150.      */
  151.     abstract public function getIntegerTypeDeclarationSQL(array $column);
  152.     /**
  153.      * Returns the SQL snippet that declares an 8 byte integer column.
  154.      *
  155.      * @param mixed[] $column
  156.      *
  157.      * @return string
  158.      */
  159.     abstract public function getBigIntTypeDeclarationSQL(array $column);
  160.     /**
  161.      * Returns the SQL snippet that declares a 2 byte integer column.
  162.      *
  163.      * @param mixed[] $column
  164.      *
  165.      * @return string
  166.      */
  167.     abstract public function getSmallIntTypeDeclarationSQL(array $column);
  168.     /**
  169.      * Returns the SQL snippet that declares common properties of an integer column.
  170.      *
  171.      * @param mixed[] $column
  172.      *
  173.      * @return string
  174.      */
  175.     abstract protected function _getCommonIntegerTypeDeclarationSQL(array $column);
  176.     /**
  177.      * Lazy load Doctrine Type Mappings.
  178.      *
  179.      * @return void
  180.      */
  181.     abstract protected function initializeDoctrineTypeMappings();
  182.     /**
  183.      * Initializes Doctrine Type Mappings with the platform defaults
  184.      * and with all additional type mappings.
  185.      */
  186.     private function initializeAllDoctrineTypeMappings(): void
  187.     {
  188.         $this->initializeDoctrineTypeMappings();
  189.         foreach (Type::getTypesMap() as $typeName => $className) {
  190.             foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) {
  191.                 $this->doctrineTypeMapping[$dbType] = $typeName;
  192.             }
  193.         }
  194.     }
  195.     /**
  196.      * Returns the SQL snippet used to declare a column that can
  197.      * store characters in the ASCII character set
  198.      *
  199.      * @param mixed[] $column
  200.      */
  201.     public function getAsciiStringTypeDeclarationSQL(array $column): string
  202.     {
  203.         return $this->getStringTypeDeclarationSQL($column);
  204.     }
  205.     /**
  206.      * Returns the SQL snippet used to declare a VARCHAR column type.
  207.      *
  208.      * @deprecated Use {@link getStringTypeDeclarationSQL()} instead.
  209.      *
  210.      * @param mixed[] $column
  211.      *
  212.      * @return string
  213.      */
  214.     public function getVarcharTypeDeclarationSQL(array $column)
  215.     {
  216.         if (isset($column['length'])) {
  217.             $lengthOmitted false;
  218.         } else {
  219.             $column['length'] = $this->getVarcharDefaultLength();
  220.             $lengthOmitted    true;
  221.         }
  222.         $fixed $column['fixed'] ?? false;
  223.         $maxLength $fixed
  224.             $this->getCharMaxLength()
  225.             : $this->getVarcharMaxLength();
  226.         if ($column['length'] > $maxLength) {
  227.             return $this->getClobTypeDeclarationSQL($column);
  228.         }
  229.         return $this->getVarcharTypeDeclarationSQLSnippet($column['length'], $fixed$lengthOmitted);
  230.     }
  231.     /**
  232.      * Returns the SQL snippet used to declare a string column type.
  233.      *
  234.      * @param mixed[] $column
  235.      *
  236.      * @return string
  237.      */
  238.     public function getStringTypeDeclarationSQL(array $column)
  239.     {
  240.         return $this->getVarcharTypeDeclarationSQL($column);
  241.     }
  242.     /**
  243.      * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
  244.      *
  245.      * @param mixed[] $column The column definition.
  246.      *
  247.      * @return string
  248.      */
  249.     public function getBinaryTypeDeclarationSQL(array $column)
  250.     {
  251.         if (isset($column['length'])) {
  252.             $lengthOmitted false;
  253.         } else {
  254.             $column['length'] = $this->getBinaryDefaultLength();
  255.             $lengthOmitted    true;
  256.         }
  257.         $fixed $column['fixed'] ?? false;
  258.         $maxLength $this->getBinaryMaxLength();
  259.         if ($column['length'] > $maxLength) {
  260.             if ($maxLength 0) {
  261.                 Deprecation::trigger(
  262.                     'doctrine/dbal',
  263.                     'https://github.com/doctrine/dbal/issues/3187',
  264.                     'Binary column length %d is greater than supported by the platform (%d).'
  265.                         ' Reduce the column length or use a BLOB column instead.',
  266.                     $column['length'],
  267.                     $maxLength,
  268.                 );
  269.             }
  270.             return $this->getBlobTypeDeclarationSQL($column);
  271.         }
  272.         return $this->getBinaryTypeDeclarationSQLSnippet($column['length'], $fixed$lengthOmitted);
  273.     }
  274.     /**
  275.      * Returns the SQL snippet to declare a GUID/UUID column.
  276.      *
  277.      * By default this maps directly to a CHAR(36) and only maps to more
  278.      * special datatypes when the underlying databases support this datatype.
  279.      *
  280.      * @param mixed[] $column
  281.      *
  282.      * @return string
  283.      */
  284.     public function getGuidTypeDeclarationSQL(array $column)
  285.     {
  286.         $column['length'] = 36;
  287.         $column['fixed']  = true;
  288.         return $this->getStringTypeDeclarationSQL($column);
  289.     }
  290.     /**
  291.      * Returns the SQL snippet to declare a JSON column.
  292.      *
  293.      * By default this maps directly to a CLOB and only maps to more
  294.      * special datatypes when the underlying databases support this datatype.
  295.      *
  296.      * @param mixed[] $column
  297.      *
  298.      * @return string
  299.      */
  300.     public function getJsonTypeDeclarationSQL(array $column)
  301.     {
  302.         return $this->getClobTypeDeclarationSQL($column);
  303.     }
  304.     /**
  305.      * @param int|false $length
  306.      * @param bool      $fixed
  307.      *
  308.      * @return string
  309.      *
  310.      * @throws Exception If not supported on this platform.
  311.      */
  312.     protected function getVarcharTypeDeclarationSQLSnippet($length$fixed/*, $lengthOmitted = false*/)
  313.     {
  314.         throw Exception::notSupported('VARCHARs not supported by Platform.');
  315.     }
  316.     /**
  317.      * Returns the SQL snippet used to declare a BINARY/VARBINARY column type.
  318.      *
  319.      * @param int|false $length The length of the column.
  320.      * @param bool      $fixed  Whether the column length is fixed.
  321.      *
  322.      * @return string
  323.      *
  324.      * @throws Exception If not supported on this platform.
  325.      */
  326.     protected function getBinaryTypeDeclarationSQLSnippet($length$fixed/*, $lengthOmitted = false*/)
  327.     {
  328.         throw Exception::notSupported('BINARY/VARBINARY column types are not supported by this platform.');
  329.     }
  330.     /**
  331.      * Returns the SQL snippet used to declare a CLOB column type.
  332.      *
  333.      * @param mixed[] $column
  334.      *
  335.      * @return string
  336.      */
  337.     abstract public function getClobTypeDeclarationSQL(array $column);
  338.     /**
  339.      * Returns the SQL Snippet used to declare a BLOB column type.
  340.      *
  341.      * @param mixed[] $column
  342.      *
  343.      * @return string
  344.      */
  345.     abstract public function getBlobTypeDeclarationSQL(array $column);
  346.     /**
  347.      * Gets the name of the platform.
  348.      *
  349.      * @deprecated Identify platforms by their class.
  350.      *
  351.      * @return string
  352.      */
  353.     abstract public function getName();
  354.     /**
  355.      * Registers a doctrine type to be used in conjunction with a column type of this platform.
  356.      *
  357.      * @param string $dbType
  358.      * @param string $doctrineType
  359.      *
  360.      * @return void
  361.      *
  362.      * @throws Exception If the type is not found.
  363.      */
  364.     public function registerDoctrineTypeMapping($dbType$doctrineType)
  365.     {
  366.         if ($this->doctrineTypeMapping === null) {
  367.             $this->initializeAllDoctrineTypeMappings();
  368.         }
  369.         if (! Types\Type::hasType($doctrineType)) {
  370.             throw Exception::typeNotFound($doctrineType);
  371.         }
  372.         $dbType                             strtolower($dbType);
  373.         $this->doctrineTypeMapping[$dbType] = $doctrineType;
  374.         $doctrineType Type::getType($doctrineType);
  375.         if (! $doctrineType->requiresSQLCommentHint($this)) {
  376.             return;
  377.         }
  378.         $this->markDoctrineTypeCommented($doctrineType);
  379.     }
  380.     /**
  381.      * Gets the Doctrine type that is mapped for the given database column type.
  382.      *
  383.      * @param string $dbType
  384.      *
  385.      * @return string
  386.      *
  387.      * @throws Exception
  388.      */
  389.     public function getDoctrineTypeMapping($dbType)
  390.     {
  391.         if ($this->doctrineTypeMapping === null) {
  392.             $this->initializeAllDoctrineTypeMappings();
  393.         }
  394.         $dbType strtolower($dbType);
  395.         if (! isset($this->doctrineTypeMapping[$dbType])) {
  396.             throw new Exception(
  397.                 'Unknown database type ' $dbType ' requested, ' . static::class . ' may not support it.',
  398.             );
  399.         }
  400.         return $this->doctrineTypeMapping[$dbType];
  401.     }
  402.     /**
  403.      * Checks if a database type is currently supported by this platform.
  404.      *
  405.      * @param string $dbType
  406.      *
  407.      * @return bool
  408.      */
  409.     public function hasDoctrineTypeMappingFor($dbType)
  410.     {
  411.         if ($this->doctrineTypeMapping === null) {
  412.             $this->initializeAllDoctrineTypeMappings();
  413.         }
  414.         $dbType strtolower($dbType);
  415.         return isset($this->doctrineTypeMapping[$dbType]);
  416.     }
  417.     /**
  418.      * Initializes the Doctrine Type comments instance variable for in_array() checks.
  419.      *
  420.      * @deprecated This API will be removed in Doctrine DBAL 4.0.
  421.      *
  422.      * @return void
  423.      */
  424.     protected function initializeCommentedDoctrineTypes()
  425.     {
  426.         Deprecation::triggerIfCalledFromOutside(
  427.             'doctrine/dbal',
  428.             'https://github.com/doctrine/dbal/pull/5058',
  429.             '%s is deprecated and will be removed in Doctrine DBAL 4.0.',
  430.             __METHOD__,
  431.         );
  432.         $this->doctrineTypeComments = [];
  433.         foreach (Type::getTypesMap() as $typeName => $className) {
  434.             $type Type::getType($typeName);
  435.             if (! $type->requiresSQLCommentHint($this)) {
  436.                 continue;
  437.             }
  438.             $this->doctrineTypeComments[] = $typeName;
  439.         }
  440.     }
  441.     /**
  442.      * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type?
  443.      *
  444.      * @deprecated Use {@link Type::requiresSQLCommentHint()} instead.
  445.      *
  446.      * @return bool
  447.      */
  448.     public function isCommentedDoctrineType(Type $doctrineType)
  449.     {
  450.         Deprecation::triggerIfCalledFromOutside(
  451.             'doctrine/dbal',
  452.             'https://github.com/doctrine/dbal/pull/5058',
  453.             '%s is deprecated and will be removed in Doctrine DBAL 4.0. Use Type::requiresSQLCommentHint() instead.',
  454.             __METHOD__,
  455.         );
  456.         if ($this->doctrineTypeComments === null) {
  457.             $this->initializeCommentedDoctrineTypes();
  458.         }
  459.         return $doctrineType->requiresSQLCommentHint($this);
  460.     }
  461.     /**
  462.      * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements.
  463.      *
  464.      * @param string|Type $doctrineType
  465.      *
  466.      * @return void
  467.      */
  468.     public function markDoctrineTypeCommented($doctrineType)
  469.     {
  470.         Deprecation::triggerIfCalledFromOutside(
  471.             'doctrine/dbal',
  472.             'https://github.com/doctrine/dbal/pull/5058',
  473.             '%s is deprecated and will be removed in Doctrine DBAL 4.0. Use Type::requiresSQLCommentHint() instead.',
  474.             __METHOD__,
  475.         );
  476.         if ($this->doctrineTypeComments === null) {
  477.             $this->initializeCommentedDoctrineTypes();
  478.         }
  479.         assert(is_array($this->doctrineTypeComments));
  480.         $this->doctrineTypeComments[] = $doctrineType instanceof Type $doctrineType->getName() : $doctrineType;
  481.     }
  482.     /**
  483.      * Gets the comment to append to a column comment that helps parsing this type in reverse engineering.
  484.      *
  485.      * @deprecated This method will be removed without replacement.
  486.      *
  487.      * @return string
  488.      */
  489.     public function getDoctrineTypeComment(Type $doctrineType)
  490.     {
  491.         Deprecation::triggerIfCalledFromOutside(
  492.             'doctrine/dbal',
  493.             'https://github.com/doctrine/dbal/pull/5107',
  494.             '%s is deprecated and will be removed in Doctrine DBAL 4.0.',
  495.             __METHOD__,
  496.         );
  497.         return '(DC2Type:' $doctrineType->getName() . ')';
  498.     }
  499.     /**
  500.      * Gets the comment of a passed column modified by potential doctrine type comment hints.
  501.      *
  502.      * @deprecated This method will be removed without replacement.
  503.      *
  504.      * @return string|null
  505.      */
  506.     protected function getColumnComment(Column $column)
  507.     {
  508.         Deprecation::triggerIfCalledFromOutside(
  509.             'doctrine/dbal',
  510.             'https://github.com/doctrine/dbal/pull/5107',
  511.             '%s is deprecated and will be removed in Doctrine DBAL 4.0.',
  512.             __METHOD__,
  513.         );
  514.         $comment $column->getComment();
  515.         if (! $this->disableTypeComments && $column->getType()->requiresSQLCommentHint($this)) {
  516.             $comment .= $this->getDoctrineTypeComment($column->getType());
  517.         }
  518.         return $comment;
  519.     }
  520.     /**
  521.      * Gets the character used for identifier quoting.
  522.      *
  523.      * @deprecated Use {@see quoteIdentifier()} to quote identifiers instead.
  524.      *
  525.      * @return string
  526.      */
  527.     public function getIdentifierQuoteCharacter()
  528.     {
  529.         Deprecation::triggerIfCalledFromOutside(
  530.             'doctrine/dbal',
  531.             'https://github.com/doctrine/dbal/pull/5388',
  532.             'AbstractPlatform::getIdentifierQuoteCharacter() is deprecated. Use quoteIdentifier() instead.',
  533.         );
  534.         return '"';
  535.     }
  536.     /**
  537.      * Gets the string portion that starts an SQL comment.
  538.      *
  539.      * @deprecated
  540.      *
  541.      * @return string
  542.      */
  543.     public function getSqlCommentStartString()
  544.     {
  545.         Deprecation::trigger(
  546.             'doctrine/dbal',
  547.             'https://github.com/doctrine/dbal/pull/4724',
  548.             'AbstractPlatform::getSqlCommentStartString() is deprecated.',
  549.         );
  550.         return '--';
  551.     }
  552.     /**
  553.      * Gets the string portion that ends an SQL comment.
  554.      *
  555.      * @deprecated
  556.      *
  557.      * @return string
  558.      */
  559.     public function getSqlCommentEndString()
  560.     {
  561.         Deprecation::trigger(
  562.             'doctrine/dbal',
  563.             'https://github.com/doctrine/dbal/pull/4724',
  564.             'AbstractPlatform::getSqlCommentEndString() is deprecated.',
  565.         );
  566.         return "\n";
  567.     }
  568.     /**
  569.      * Gets the maximum length of a char column.
  570.      *
  571.      * @deprecated
  572.      */
  573.     public function getCharMaxLength(): int
  574.     {
  575.         Deprecation::triggerIfCalledFromOutside(
  576.             'doctrine/dbal',
  577.             'https://github.com/doctrine/dbal/issues/3263',
  578.             'AbstractPlatform::getCharMaxLength() is deprecated.',
  579.         );
  580.         return $this->getVarcharMaxLength();
  581.     }
  582.     /**
  583.      * Gets the maximum length of a varchar column.
  584.      *
  585.      * @deprecated
  586.      *
  587.      * @return int
  588.      */
  589.     public function getVarcharMaxLength()
  590.     {
  591.         Deprecation::triggerIfCalledFromOutside(
  592.             'doctrine/dbal',
  593.             'https://github.com/doctrine/dbal/issues/3263',
  594.             'AbstractPlatform::getVarcharMaxLength() is deprecated.',
  595.         );
  596.         return 4000;
  597.     }
  598.     /**
  599.      * Gets the default length of a varchar column.
  600.      *
  601.      * @deprecated
  602.      *
  603.      * @return int
  604.      */
  605.     public function getVarcharDefaultLength()
  606.     {
  607.         Deprecation::triggerIfCalledFromOutside(
  608.             'doctrine/dbal',
  609.             'https://github.com/doctrine/dbal/issues/3263',
  610.             'Relying on the default varchar column length is deprecated, specify the length explicitly.',
  611.         );
  612.         return 255;
  613.     }
  614.     /**
  615.      * Gets the maximum length of a binary column.
  616.      *
  617.      * @deprecated
  618.      *
  619.      * @return int
  620.      */
  621.     public function getBinaryMaxLength()
  622.     {
  623.         Deprecation::triggerIfCalledFromOutside(
  624.             'doctrine/dbal',
  625.             'https://github.com/doctrine/dbal/issues/3263',
  626.             'AbstractPlatform::getBinaryMaxLength() is deprecated.',
  627.         );
  628.         return 4000;
  629.     }
  630.     /**
  631.      * Gets the default length of a binary column.
  632.      *
  633.      * @deprecated
  634.      *
  635.      * @return int
  636.      */
  637.     public function getBinaryDefaultLength()
  638.     {
  639.         Deprecation::trigger(
  640.             'doctrine/dbal',
  641.             'https://github.com/doctrine/dbal/issues/3263',
  642.             'Relying on the default binary column length is deprecated, specify the length explicitly.',
  643.         );
  644.         return 255;
  645.     }
  646.     /**
  647.      * Gets all SQL wildcard characters of the platform.
  648.      *
  649.      * @deprecated Use {@see AbstractPlatform::getLikeWildcardCharacters()} instead.
  650.      *
  651.      * @return string[]
  652.      */
  653.     public function getWildcards()
  654.     {
  655.         Deprecation::trigger(
  656.             'doctrine/dbal',
  657.             'https://github.com/doctrine/dbal/pull/4724',
  658.             'AbstractPlatform::getWildcards() is deprecated.'
  659.             ' Use AbstractPlatform::getLikeWildcardCharacters() instead.',
  660.         );
  661.         return ['%''_'];
  662.     }
  663.     /**
  664.      * Returns the regular expression operator.
  665.      *
  666.      * @return string
  667.      *
  668.      * @throws Exception If not supported on this platform.
  669.      */
  670.     public function getRegexpExpression()
  671.     {
  672.         throw Exception::notSupported(__METHOD__);
  673.     }
  674.     /**
  675.      * Returns the SQL snippet to get the average value of a column.
  676.      *
  677.      * @deprecated Use AVG() in SQL instead.
  678.      *
  679.      * @param string $column The column to use.
  680.      *
  681.      * @return string Generated SQL including an AVG aggregate function.
  682.      */
  683.     public function getAvgExpression($column)
  684.     {
  685.         Deprecation::trigger(
  686.             'doctrine/dbal',
  687.             'https://github.com/doctrine/dbal/pull/4724',
  688.             'AbstractPlatform::getAvgExpression() is deprecated. Use AVG() in SQL instead.',
  689.         );
  690.         return 'AVG(' $column ')';
  691.     }
  692.     /**
  693.      * Returns the SQL snippet to get the number of rows (without a NULL value) of a column.
  694.      *
  695.      * If a '*' is used instead of a column the number of selected rows is returned.
  696.      *
  697.      * @deprecated Use COUNT() in SQL instead.
  698.      *
  699.      * @param string|int $column The column to use.
  700.      *
  701.      * @return string Generated SQL including a COUNT aggregate function.
  702.      */
  703.     public function getCountExpression($column)
  704.     {
  705.         Deprecation::trigger(
  706.             'doctrine/dbal',
  707.             'https://github.com/doctrine/dbal/pull/4724',
  708.             'AbstractPlatform::getCountExpression() is deprecated. Use COUNT() in SQL instead.',
  709.         );
  710.         return 'COUNT(' $column ')';
  711.     }
  712.     /**
  713.      * Returns the SQL snippet to get the highest value of a column.
  714.      *
  715.      * @deprecated Use MAX() in SQL instead.
  716.      *
  717.      * @param string $column The column to use.
  718.      *
  719.      * @return string Generated SQL including a MAX aggregate function.
  720.      */
  721.     public function getMaxExpression($column)
  722.     {
  723.         Deprecation::trigger(
  724.             'doctrine/dbal',
  725.             'https://github.com/doctrine/dbal/pull/4724',
  726.             'AbstractPlatform::getMaxExpression() is deprecated. Use MAX() in SQL instead.',
  727.         );
  728.         return 'MAX(' $column ')';
  729.     }
  730.     /**
  731.      * Returns the SQL snippet to get the lowest value of a column.
  732.      *
  733.      * @deprecated Use MIN() in SQL instead.
  734.      *
  735.      * @param string $column The column to use.
  736.      *
  737.      * @return string Generated SQL including a MIN aggregate function.
  738.      */
  739.     public function getMinExpression($column)
  740.     {
  741.         Deprecation::trigger(
  742.             'doctrine/dbal',
  743.             'https://github.com/doctrine/dbal/pull/4724',
  744.             'AbstractPlatform::getMinExpression() is deprecated. Use MIN() in SQL instead.',
  745.         );
  746.         return 'MIN(' $column ')';
  747.     }
  748.     /**
  749.      * Returns the SQL snippet to get the total sum of a column.
  750.      *
  751.      * @deprecated Use SUM() in SQL instead.
  752.      *
  753.      * @param string $column The column to use.
  754.      *
  755.      * @return string Generated SQL including a SUM aggregate function.
  756.      */
  757.     public function getSumExpression($column)
  758.     {
  759.         Deprecation::trigger(
  760.             'doctrine/dbal',
  761.             'https://github.com/doctrine/dbal/pull/4724',
  762.             'AbstractPlatform::getSumExpression() is deprecated. Use SUM() in SQL instead.',
  763.         );
  764.         return 'SUM(' $column ')';
  765.     }
  766.     // scalar functions
  767.     /**
  768.      * Returns the SQL snippet to get the md5 sum of a column.
  769.      *
  770.      * Note: Not SQL92, but common functionality.
  771.      *
  772.      * @deprecated
  773.      *
  774.      * @param string $column
  775.      *
  776.      * @return string
  777.      */
  778.     public function getMd5Expression($column)
  779.     {
  780.         Deprecation::trigger(
  781.             'doctrine/dbal',
  782.             'https://github.com/doctrine/dbal/pull/4724',
  783.             'AbstractPlatform::getMd5Expression() is deprecated.',
  784.         );
  785.         return 'MD5(' $column ')';
  786.     }
  787.     /**
  788.      * Returns the SQL snippet to get the length of a text column in characters.
  789.      *
  790.      * @param string $column
  791.      *
  792.      * @return string
  793.      */
  794.     public function getLengthExpression($column)
  795.     {
  796.         return 'LENGTH(' $column ')';
  797.     }
  798.     /**
  799.      * Returns the SQL snippet to get the squared value of a column.
  800.      *
  801.      * @deprecated Use SQRT() in SQL instead.
  802.      *
  803.      * @param string $column The column to use.
  804.      *
  805.      * @return string Generated SQL including an SQRT aggregate function.
  806.      */
  807.     public function getSqrtExpression($column)
  808.     {
  809.         Deprecation::trigger(
  810.             'doctrine/dbal',
  811.             'https://github.com/doctrine/dbal/pull/4724',
  812.             'AbstractPlatform::getSqrtExpression() is deprecated. Use SQRT() in SQL instead.',
  813.         );
  814.         return 'SQRT(' $column ')';
  815.     }
  816.     /**
  817.      * Returns the SQL snippet to round a numeric column to the number of decimals specified.
  818.      *
  819.      * @deprecated Use ROUND() in SQL instead.
  820.      *
  821.      * @param string     $column
  822.      * @param string|int $decimals
  823.      *
  824.      * @return string
  825.      */
  826.     public function getRoundExpression($column$decimals 0)
  827.     {
  828.         Deprecation::trigger(
  829.             'doctrine/dbal',
  830.             'https://github.com/doctrine/dbal/pull/4724',
  831.             'AbstractPlatform::getRoundExpression() is deprecated. Use ROUND() in SQL instead.',
  832.         );
  833.         return 'ROUND(' $column ', ' $decimals ')';
  834.     }
  835.     /**
  836.      * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2.
  837.      *
  838.      * @param string $expression1
  839.      * @param string $expression2
  840.      *
  841.      * @return string
  842.      */
  843.     public function getModExpression($expression1$expression2)
  844.     {
  845.         return 'MOD(' $expression1 ', ' $expression2 ')';
  846.     }
  847.     /**
  848.      * Returns the SQL snippet to trim a string.
  849.      *
  850.      * @param string      $str  The expression to apply the trim to.
  851.      * @param int         $mode The position of the trim (leading/trailing/both).
  852.      * @param string|bool $char The char to trim, has to be quoted already. Defaults to space.
  853.      *
  854.      * @return string
  855.      */
  856.     public function getTrimExpression($str$mode TrimMode::UNSPECIFIED$char false)
  857.     {
  858.         $expression '';
  859.         switch ($mode) {
  860.             case TrimMode::LEADING:
  861.                 $expression 'LEADING ';
  862.                 break;
  863.             case TrimMode::TRAILING:
  864.                 $expression 'TRAILING ';
  865.                 break;
  866.             case TrimMode::BOTH:
  867.                 $expression 'BOTH ';
  868.                 break;
  869.         }
  870.         if ($char !== false) {
  871.             $expression .= $char ' ';
  872.         }
  873.         if ($mode !== TrimMode::UNSPECIFIED || $char !== false) {
  874.             $expression .= 'FROM ';
  875.         }
  876.         return 'TRIM(' $expression $str ')';
  877.     }
  878.     /**
  879.      * Returns the SQL snippet to trim trailing space characters from the expression.
  880.      *
  881.      * @deprecated Use RTRIM() in SQL instead.
  882.      *
  883.      * @param string $str Literal string or column name.
  884.      *
  885.      * @return string
  886.      */
  887.     public function getRtrimExpression($str)
  888.     {
  889.         Deprecation::trigger(
  890.             'doctrine/dbal',
  891.             'https://github.com/doctrine/dbal/pull/4724',
  892.             'AbstractPlatform::getRtrimExpression() is deprecated. Use RTRIM() in SQL instead.',
  893.         );
  894.         return 'RTRIM(' $str ')';
  895.     }
  896.     /**
  897.      * Returns the SQL snippet to trim leading space characters from the expression.
  898.      *
  899.      * @deprecated Use LTRIM() in SQL instead.
  900.      *
  901.      * @param string $str Literal string or column name.
  902.      *
  903.      * @return string
  904.      */
  905.     public function getLtrimExpression($str)
  906.     {
  907.         Deprecation::trigger(
  908.             'doctrine/dbal',
  909.             'https://github.com/doctrine/dbal/pull/4724',
  910.             'AbstractPlatform::getLtrimExpression() is deprecated. Use LTRIM() in SQL instead.',
  911.         );
  912.         return 'LTRIM(' $str ')';
  913.     }
  914.     /**
  915.      * Returns the SQL snippet to change all characters from the expression to uppercase,
  916.      * according to the current character set mapping.
  917.      *
  918.      * @deprecated Use UPPER() in SQL instead.
  919.      *
  920.      * @param string $str Literal string or column name.
  921.      *
  922.      * @return string
  923.      */
  924.     public function getUpperExpression($str)
  925.     {
  926.         Deprecation::trigger(
  927.             'doctrine/dbal',
  928.             'https://github.com/doctrine/dbal/pull/4724',
  929.             'AbstractPlatform::getUpperExpression() is deprecated. Use UPPER() in SQL instead.',
  930.         );
  931.         return 'UPPER(' $str ')';
  932.     }
  933.     /**
  934.      * Returns the SQL snippet to change all characters from the expression to lowercase,
  935.      * according to the current character set mapping.
  936.      *
  937.      * @deprecated Use LOWER() in SQL instead.
  938.      *
  939.      * @param string $str Literal string or column name.
  940.      *
  941.      * @return string
  942.      */
  943.     public function getLowerExpression($str)
  944.     {
  945.         Deprecation::trigger(
  946.             'doctrine/dbal',
  947.             'https://github.com/doctrine/dbal/pull/4724',
  948.             'AbstractPlatform::getLowerExpression() is deprecated. Use LOWER() in SQL instead.',
  949.         );
  950.         return 'LOWER(' $str ')';
  951.     }
  952.     /**
  953.      * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str.
  954.      *
  955.      * @param string           $str      Literal string.
  956.      * @param string           $substr   Literal string to find.
  957.      * @param string|int|false $startPos Position to start at, beginning of string by default.
  958.      *
  959.      * @return string
  960.      *
  961.      * @throws Exception If not supported on this platform.
  962.      */
  963.     public function getLocateExpression($str$substr$startPos false)
  964.     {
  965.         throw Exception::notSupported(__METHOD__);
  966.     }
  967.     /**
  968.      * Returns the SQL snippet to get the current system date.
  969.      *
  970.      * @deprecated Generate dates within the application.
  971.      *
  972.      * @return string
  973.      */
  974.     public function getNowExpression()
  975.     {
  976.         Deprecation::trigger(
  977.             'doctrine/dbal',
  978.             'https://github.com/doctrine/dbal/pull/4753',
  979.             'AbstractPlatform::getNowExpression() is deprecated. Generate dates within the application.',
  980.         );
  981.         return 'NOW()';
  982.     }
  983.     /**
  984.      * Returns a SQL snippet to get a substring inside an SQL statement.
  985.      *
  986.      * Note: Not SQL92, but common functionality.
  987.      *
  988.      * SQLite only supports the 2 parameter variant of this function.
  989.      *
  990.      * @param string          $string An sql string literal or column name/alias.
  991.      * @param string|int      $start  Where to start the substring portion.
  992.      * @param string|int|null $length The substring portion length.
  993.      *
  994.      * @return string
  995.      */
  996.     public function getSubstringExpression($string$start$length null)
  997.     {
  998.         if ($length === null) {
  999.             return 'SUBSTRING(' $string ' FROM ' $start ')';
  1000.         }
  1001.         return 'SUBSTRING(' $string ' FROM ' $start ' FOR ' $length ')';
  1002.     }
  1003.     /**
  1004.      * Returns a SQL snippet to concatenate the given expressions.
  1005.      *
  1006.      * Accepts an arbitrary number of string parameters. Each parameter must contain an expression.
  1007.      *
  1008.      * @return string
  1009.      */
  1010.     public function getConcatExpression()
  1011.     {
  1012.         return implode(' || 'func_get_args());
  1013.     }
  1014.     /**
  1015.      * Returns the SQL for a logical not.
  1016.      *
  1017.      * Example:
  1018.      * <code>
  1019.      * $q = new Doctrine_Query();
  1020.      * $e = $q->expr;
  1021.      * $q->select('*')->from('table')
  1022.      *   ->where($e->eq('id', $e->not('null'));
  1023.      * </code>
  1024.      *
  1025.      * @deprecated Use NOT() in SQL instead.
  1026.      *
  1027.      * @param string $expression
  1028.      *
  1029.      * @return string The logical expression.
  1030.      */
  1031.     public function getNotExpression($expression)
  1032.     {
  1033.         Deprecation::trigger(
  1034.             'doctrine/dbal',
  1035.             'https://github.com/doctrine/dbal/pull/4724',
  1036.             'AbstractPlatform::getNotExpression() is deprecated. Use NOT() in SQL instead.',
  1037.         );
  1038.         return 'NOT(' $expression ')';
  1039.     }
  1040.     /**
  1041.      * Returns the SQL that checks if an expression is null.
  1042.      *
  1043.      * @deprecated Use IS NULL in SQL instead.
  1044.      *
  1045.      * @param string $expression The expression that should be compared to null.
  1046.      *
  1047.      * @return string The logical expression.
  1048.      */
  1049.     public function getIsNullExpression($expression)
  1050.     {
  1051.         Deprecation::trigger(
  1052.             'doctrine/dbal',
  1053.             'https://github.com/doctrine/dbal/pull/4724',
  1054.             'AbstractPlatform::getIsNullExpression() is deprecated. Use IS NULL in SQL instead.',
  1055.         );
  1056.         return $expression ' IS NULL';
  1057.     }
  1058.     /**
  1059.      * Returns the SQL that checks if an expression is not null.
  1060.      *
  1061.      * @deprecated Use IS NOT NULL in SQL instead.
  1062.      *
  1063.      * @param string $expression The expression that should be compared to null.
  1064.      *
  1065.      * @return string The logical expression.
  1066.      */
  1067.     public function getIsNotNullExpression($expression)
  1068.     {
  1069.         Deprecation::trigger(
  1070.             'doctrine/dbal',
  1071.             'https://github.com/doctrine/dbal/pull/4724',
  1072.             'AbstractPlatform::getIsNotNullExpression() is deprecated. Use IS NOT NULL in SQL instead.',
  1073.         );
  1074.         return $expression ' IS NOT NULL';
  1075.     }
  1076.     /**
  1077.      * Returns the SQL that checks if an expression evaluates to a value between two values.
  1078.      *
  1079.      * The parameter $expression is checked if it is between $value1 and $value2.
  1080.      *
  1081.      * Note: There is a slight difference in the way BETWEEN works on some databases.
  1082.      * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
  1083.      * independence you should avoid using between().
  1084.      *
  1085.      * @deprecated Use BETWEEN in SQL instead.
  1086.      *
  1087.      * @param string $expression The value to compare to.
  1088.      * @param string $value1     The lower value to compare with.
  1089.      * @param string $value2     The higher value to compare with.
  1090.      *
  1091.      * @return string The logical expression.
  1092.      */
  1093.     public function getBetweenExpression($expression$value1$value2)
  1094.     {
  1095.         Deprecation::trigger(
  1096.             'doctrine/dbal',
  1097.             'https://github.com/doctrine/dbal/pull/4724',
  1098.             'AbstractPlatform::getBetweenExpression() is deprecated. Use BETWEEN in SQL instead.',
  1099.         );
  1100.         return $expression ' BETWEEN ' $value1 ' AND ' $value2;
  1101.     }
  1102.     /**
  1103.      * Returns the SQL to get the arccosine of a value.
  1104.      *
  1105.      * @deprecated Use ACOS() in SQL instead.
  1106.      *
  1107.      * @param string $value
  1108.      *
  1109.      * @return string
  1110.      */
  1111.     public function getAcosExpression($value)
  1112.     {
  1113.         Deprecation::trigger(
  1114.             'doctrine/dbal',
  1115.             'https://github.com/doctrine/dbal/pull/4724',
  1116.             'AbstractPlatform::getAcosExpression() is deprecated. Use ACOS() in SQL instead.',
  1117.         );
  1118.         return 'ACOS(' $value ')';
  1119.     }
  1120.     /**
  1121.      * Returns the SQL to get the sine of a value.
  1122.      *
  1123.      * @deprecated Use SIN() in SQL instead.
  1124.      *
  1125.      * @param string $value
  1126.      *
  1127.      * @return string
  1128.      */
  1129.     public function getSinExpression($value)
  1130.     {
  1131.         Deprecation::trigger(
  1132.             'doctrine/dbal',
  1133.             'https://github.com/doctrine/dbal/pull/4724',
  1134.             'AbstractPlatform::getSinExpression() is deprecated. Use SIN() in SQL instead.',
  1135.         );
  1136.         return 'SIN(' $value ')';
  1137.     }
  1138.     /**
  1139.      * Returns the SQL to get the PI value.
  1140.      *
  1141.      * @deprecated Use PI() in SQL instead.
  1142.      *
  1143.      * @return string
  1144.      */
  1145.     public function getPiExpression()
  1146.     {
  1147.         Deprecation::trigger(
  1148.             'doctrine/dbal',
  1149.             'https://github.com/doctrine/dbal/pull/4724',
  1150.             'AbstractPlatform::getPiExpression() is deprecated. Use PI() in SQL instead.',
  1151.         );
  1152.         return 'PI()';
  1153.     }
  1154.     /**
  1155.      * Returns the SQL to get the cosine of a value.
  1156.      *
  1157.      * @deprecated Use COS() in SQL instead.
  1158.      *
  1159.      * @param string $value
  1160.      *
  1161.      * @return string
  1162.      */
  1163.     public function getCosExpression($value)
  1164.     {
  1165.         Deprecation::trigger(
  1166.             'doctrine/dbal',
  1167.             'https://github.com/doctrine/dbal/pull/4724',
  1168.             'AbstractPlatform::getCosExpression() is deprecated. Use COS() in SQL instead.',
  1169.         );
  1170.         return 'COS(' $value ')';
  1171.     }
  1172.     /**
  1173.      * Returns the SQL to calculate the difference in days between the two passed dates.
  1174.      *
  1175.      * Computes diff = date1 - date2.
  1176.      *
  1177.      * @param string $date1
  1178.      * @param string $date2
  1179.      *
  1180.      * @return string
  1181.      *
  1182.      * @throws Exception If not supported on this platform.
  1183.      */
  1184.     public function getDateDiffExpression($date1$date2)
  1185.     {
  1186.         throw Exception::notSupported(__METHOD__);
  1187.     }
  1188.     /**
  1189.      * Returns the SQL to add the number of given seconds to a date.
  1190.      *
  1191.      * @param string             $date
  1192.      * @param int|numeric-string $seconds
  1193.      *
  1194.      * @return string
  1195.      *
  1196.      * @throws Exception If not supported on this platform.
  1197.      */
  1198.     public function getDateAddSecondsExpression($date$seconds)
  1199.     {
  1200.         if (is_int($seconds)) {
  1201.             Deprecation::trigger(
  1202.                 'doctrine/dbal',
  1203.                 'https://github.com/doctrine/dbal/pull/3498',
  1204.                 'Passing $seconds as an integer is deprecated. Pass it as a numeric string instead.',
  1205.             );
  1206.         }
  1207.         return $this->getDateArithmeticIntervalExpression($date'+'$secondsDateIntervalUnit::SECOND);
  1208.     }
  1209.     /**
  1210.      * Returns the SQL to subtract the number of given seconds from a date.
  1211.      *
  1212.      * @param string             $date
  1213.      * @param int|numeric-string $seconds
  1214.      *
  1215.      * @return string
  1216.      *
  1217.      * @throws Exception If not supported on this platform.
  1218.      */
  1219.     public function getDateSubSecondsExpression($date$seconds)
  1220.     {
  1221.         if (is_int($seconds)) {
  1222.             Deprecation::trigger(
  1223.                 'doctrine/dbal',
  1224.                 'https://github.com/doctrine/dbal/pull/3498',
  1225.                 'Passing $seconds as an integer is deprecated. Pass it as a numeric string instead.',
  1226.             );
  1227.         }
  1228.         return $this->getDateArithmeticIntervalExpression($date'-'$secondsDateIntervalUnit::SECOND);
  1229.     }
  1230.     /**
  1231.      * Returns the SQL to add the number of given minutes to a date.
  1232.      *
  1233.      * @param string             $date
  1234.      * @param int|numeric-string $minutes
  1235.      *
  1236.      * @return string
  1237.      *
  1238.      * @throws Exception If not supported on this platform.
  1239.      */
  1240.     public function getDateAddMinutesExpression($date$minutes)
  1241.     {
  1242.         if (is_int($minutes)) {
  1243.             Deprecation::trigger(
  1244.                 'doctrine/dbal',
  1245.                 'https://github.com/doctrine/dbal/pull/3498',
  1246.                 'Passing $minutes as an integer is deprecated. Pass it as a numeric string instead.',
  1247.             );
  1248.         }
  1249.         return $this->getDateArithmeticIntervalExpression($date'+'$minutesDateIntervalUnit::MINUTE);
  1250.     }
  1251.     /**
  1252.      * Returns the SQL to subtract the number of given minutes from a date.
  1253.      *
  1254.      * @param string             $date
  1255.      * @param int|numeric-string $minutes
  1256.      *
  1257.      * @return string
  1258.      *
  1259.      * @throws Exception If not supported on this platform.
  1260.      */
  1261.     public function getDateSubMinutesExpression($date$minutes)
  1262.     {
  1263.         if (is_int($minutes)) {
  1264.             Deprecation::trigger(
  1265.                 'doctrine/dbal',
  1266.                 'https://github.com/doctrine/dbal/pull/3498',
  1267.                 'Passing $minutes as an integer is deprecated. Pass it as a numeric string instead.',
  1268.             );
  1269.         }
  1270.         return $this->getDateArithmeticIntervalExpression($date'-'$minutesDateIntervalUnit::MINUTE);
  1271.     }
  1272.     /**
  1273.      * Returns the SQL to add the number of given hours to a date.
  1274.      *
  1275.      * @param string             $date
  1276.      * @param int|numeric-string $hours
  1277.      *
  1278.      * @return string
  1279.      *
  1280.      * @throws Exception If not supported on this platform.
  1281.      */
  1282.     public function getDateAddHourExpression($date$hours)
  1283.     {
  1284.         if (is_int($hours)) {
  1285.             Deprecation::trigger(
  1286.                 'doctrine/dbal',
  1287.                 'https://github.com/doctrine/dbal/pull/3498',
  1288.                 'Passing $hours as an integer is deprecated. Pass it as a numeric string instead.',
  1289.             );
  1290.         }
  1291.         return $this->getDateArithmeticIntervalExpression($date'+'$hoursDateIntervalUnit::HOUR);
  1292.     }
  1293.     /**
  1294.      * Returns the SQL to subtract the number of given hours to a date.
  1295.      *
  1296.      * @param string             $date
  1297.      * @param int|numeric-string $hours
  1298.      *
  1299.      * @return string
  1300.      *
  1301.      * @throws Exception If not supported on this platform.
  1302.      */
  1303.     public function getDateSubHourExpression($date$hours)
  1304.     {
  1305.         if (is_int($hours)) {
  1306.             Deprecation::trigger(
  1307.                 'doctrine/dbal',
  1308.                 'https://github.com/doctrine/dbal/pull/3498',
  1309.                 'Passing $hours as an integer is deprecated. Pass it as a numeric string instead.',
  1310.             );
  1311.         }
  1312.         return $this->getDateArithmeticIntervalExpression($date'-'$hoursDateIntervalUnit::HOUR);
  1313.     }
  1314.     /**
  1315.      * Returns the SQL to add the number of given days to a date.
  1316.      *
  1317.      * @param string             $date
  1318.      * @param int|numeric-string $days
  1319.      *
  1320.      * @return string
  1321.      *
  1322.      * @throws Exception If not supported on this platform.
  1323.      */
  1324.     public function getDateAddDaysExpression($date$days)
  1325.     {
  1326.         if (is_int($days)) {
  1327.             Deprecation::trigger(
  1328.                 'doctrine/dbal',
  1329.                 'https://github.com/doctrine/dbal/pull/3498',
  1330.                 'Passing $days as an integer is deprecated. Pass it as a numeric string instead.',
  1331.             );
  1332.         }
  1333.         return $this->getDateArithmeticIntervalExpression($date'+'$daysDateIntervalUnit::DAY);
  1334.     }
  1335.     /**
  1336.      * Returns the SQL to subtract the number of given days to a date.
  1337.      *
  1338.      * @param string             $date
  1339.      * @param int|numeric-string $days
  1340.      *
  1341.      * @return string
  1342.      *
  1343.      * @throws Exception If not supported on this platform.
  1344.      */
  1345.     public function getDateSubDaysExpression($date$days)
  1346.     {
  1347.         if (is_int($days)) {
  1348.             Deprecation::trigger(
  1349.                 'doctrine/dbal',
  1350.                 'https://github.com/doctrine/dbal/pull/3498',
  1351.                 'Passing $days as an integer is deprecated. Pass it as a numeric string instead.',
  1352.             );
  1353.         }
  1354.         return $this->getDateArithmeticIntervalExpression($date'-'$daysDateIntervalUnit::DAY);
  1355.     }
  1356.     /**
  1357.      * Returns the SQL to add the number of given weeks to a date.
  1358.      *
  1359.      * @param string             $date
  1360.      * @param int|numeric-string $weeks
  1361.      *
  1362.      * @return string
  1363.      *
  1364.      * @throws Exception If not supported on this platform.
  1365.      */
  1366.     public function getDateAddWeeksExpression($date$weeks)
  1367.     {
  1368.         if (is_int($weeks)) {
  1369.             Deprecation::trigger(
  1370.                 'doctrine/dbal',
  1371.                 'https://github.com/doctrine/dbal/pull/3498',
  1372.                 'Passing $weeks as an integer is deprecated. Pass it as a numeric string instead.',
  1373.             );
  1374.         }
  1375.         return $this->getDateArithmeticIntervalExpression($date'+'$weeksDateIntervalUnit::WEEK);
  1376.     }
  1377.     /**
  1378.      * Returns the SQL to subtract the number of given weeks from a date.
  1379.      *
  1380.      * @param string             $date
  1381.      * @param int|numeric-string $weeks
  1382.      *
  1383.      * @return string
  1384.      *
  1385.      * @throws Exception If not supported on this platform.
  1386.      */
  1387.     public function getDateSubWeeksExpression($date$weeks)
  1388.     {
  1389.         if (is_int($weeks)) {
  1390.             Deprecation::trigger(
  1391.                 'doctrine/dbal',
  1392.                 'https://github.com/doctrine/dbal/pull/3498',
  1393.                 'Passing $weeks as an integer is deprecated. Pass it as a numeric string instead.',
  1394.             );
  1395.         }
  1396.         return $this->getDateArithmeticIntervalExpression($date'-'$weeksDateIntervalUnit::WEEK);
  1397.     }
  1398.     /**
  1399.      * Returns the SQL to add the number of given months to a date.
  1400.      *
  1401.      * @param string             $date
  1402.      * @param int|numeric-string $months
  1403.      *
  1404.      * @return string
  1405.      *
  1406.      * @throws Exception If not supported on this platform.
  1407.      */
  1408.     public function getDateAddMonthExpression($date$months)
  1409.     {
  1410.         if (is_int($months)) {
  1411.             Deprecation::trigger(
  1412.                 'doctrine/dbal',
  1413.                 'https://github.com/doctrine/dbal/pull/3498',
  1414.                 'Passing $months as an integer is deprecated. Pass it as a numeric string instead.',
  1415.             );
  1416.         }
  1417.         return $this->getDateArithmeticIntervalExpression($date'+'$monthsDateIntervalUnit::MONTH);
  1418.     }
  1419.     /**
  1420.      * Returns the SQL to subtract the number of given months to a date.
  1421.      *
  1422.      * @param string             $date
  1423.      * @param int|numeric-string $months
  1424.      *
  1425.      * @return string
  1426.      *
  1427.      * @throws Exception If not supported on this platform.
  1428.      */
  1429.     public function getDateSubMonthExpression($date$months)
  1430.     {
  1431.         if (is_int($months)) {
  1432.             Deprecation::trigger(
  1433.                 'doctrine/dbal',
  1434.                 'https://github.com/doctrine/dbal/pull/3498',
  1435.                 'Passing $months as an integer is deprecated. Pass it as a numeric string instead.',
  1436.             );
  1437.         }
  1438.         return $this->getDateArithmeticIntervalExpression($date'-'$monthsDateIntervalUnit::MONTH);
  1439.     }
  1440.     /**
  1441.      * Returns the SQL to add the number of given quarters to a date.
  1442.      *
  1443.      * @param string             $date
  1444.      * @param int|numeric-string $quarters
  1445.      *
  1446.      * @return string
  1447.      *
  1448.      * @throws Exception If not supported on this platform.
  1449.      */
  1450.     public function getDateAddQuartersExpression($date$quarters)
  1451.     {
  1452.         if (is_int($quarters)) {
  1453.             Deprecation::trigger(
  1454.                 'doctrine/dbal',
  1455.                 'https://github.com/doctrine/dbal/pull/3498',
  1456.                 'Passing $quarters as an integer is deprecated. Pass it as a numeric string instead.',
  1457.             );
  1458.         }
  1459.         return $this->getDateArithmeticIntervalExpression($date'+'$quartersDateIntervalUnit::QUARTER);
  1460.     }
  1461.     /**
  1462.      * Returns the SQL to subtract the number of given quarters from a date.
  1463.      *
  1464.      * @param string             $date
  1465.      * @param int|numeric-string $quarters
  1466.      *
  1467.      * @return string
  1468.      *
  1469.      * @throws Exception If not supported on this platform.
  1470.      */
  1471.     public function getDateSubQuartersExpression($date$quarters)
  1472.     {
  1473.         if (is_int($quarters)) {
  1474.             Deprecation::trigger(
  1475.                 'doctrine/dbal',
  1476.                 'https://github.com/doctrine/dbal/pull/3498',
  1477.                 'Passing $quarters as an integer is deprecated. Pass it as a numeric string instead.',
  1478.             );
  1479.         }
  1480.         return $this->getDateArithmeticIntervalExpression($date'-'$quartersDateIntervalUnit::QUARTER);
  1481.     }
  1482.     /**
  1483.      * Returns the SQL to add the number of given years to a date.
  1484.      *
  1485.      * @param string             $date
  1486.      * @param int|numeric-string $years
  1487.      *
  1488.      * @return string
  1489.      *
  1490.      * @throws Exception If not supported on this platform.
  1491.      */
  1492.     public function getDateAddYearsExpression($date$years)
  1493.     {
  1494.         if (is_int($years)) {
  1495.             Deprecation::trigger(
  1496.                 'doctrine/dbal',
  1497.                 'https://github.com/doctrine/dbal/pull/3498',
  1498.                 'Passing $years as an integer is deprecated. Pass it as a numeric string instead.',
  1499.             );
  1500.         }
  1501.         return $this->getDateArithmeticIntervalExpression($date'+'$yearsDateIntervalUnit::YEAR);
  1502.     }
  1503.     /**
  1504.      * Returns the SQL to subtract the number of given years from a date.
  1505.      *
  1506.      * @param string             $date
  1507.      * @param int|numeric-string $years
  1508.      *
  1509.      * @return string
  1510.      *
  1511.      * @throws Exception If not supported on this platform.
  1512.      */
  1513.     public function getDateSubYearsExpression($date$years)
  1514.     {
  1515.         if (is_int($years)) {
  1516.             Deprecation::trigger(
  1517.                 'doctrine/dbal',
  1518.                 'https://github.com/doctrine/dbal/pull/3498',
  1519.                 'Passing $years as an integer is deprecated. Pass it as a numeric string instead.',
  1520.             );
  1521.         }
  1522.         return $this->getDateArithmeticIntervalExpression($date'-'$yearsDateIntervalUnit::YEAR);
  1523.     }
  1524.     /**
  1525.      * Returns the SQL for a date arithmetic expression.
  1526.      *
  1527.      * @param string             $date     The column or literal representing a date
  1528.      *                                     to perform the arithmetic operation on.
  1529.      * @param string             $operator The arithmetic operator (+ or -).
  1530.      * @param int|numeric-string $interval The interval that shall be calculated into the date.
  1531.      * @param string             $unit     The unit of the interval that shall be calculated into the date.
  1532.      *                                     One of the {@see DateIntervalUnit} constants.
  1533.      *
  1534.      * @return string
  1535.      *
  1536.      * @throws Exception If not supported on this platform.
  1537.      */
  1538.     protected function getDateArithmeticIntervalExpression($date$operator$interval$unit)
  1539.     {
  1540.         throw Exception::notSupported(__METHOD__);
  1541.     }
  1542.     /**
  1543.      * Returns the SQL bit AND comparison expression.
  1544.      *
  1545.      * @param string $value1
  1546.      * @param string $value2
  1547.      *
  1548.      * @return string
  1549.      */
  1550.     public function getBitAndComparisonExpression($value1$value2)
  1551.     {
  1552.         return '(' $value1 ' & ' $value2 ')';
  1553.     }
  1554.     /**
  1555.      * Returns the SQL bit OR comparison expression.
  1556.      *
  1557.      * @param string $value1
  1558.      * @param string $value2
  1559.      *
  1560.      * @return string
  1561.      */
  1562.     public function getBitOrComparisonExpression($value1$value2)
  1563.     {
  1564.         return '(' $value1 ' | ' $value2 ')';
  1565.     }
  1566.     /**
  1567.      * Returns the SQL expression which represents the currently selected database.
  1568.      */
  1569.     abstract public function getCurrentDatabaseExpression(): string;
  1570.     /**
  1571.      * Returns the FOR UPDATE expression.
  1572.      *
  1573.      * @return string
  1574.      */
  1575.     public function getForUpdateSQL()
  1576.     {
  1577.         return 'FOR UPDATE';
  1578.     }
  1579.     /**
  1580.      * Honors that some SQL vendors such as MsSql use table hints for locking instead of the
  1581.      * ANSI SQL FOR UPDATE specification.
  1582.      *
  1583.      * @param string $fromClause The FROM clause to append the hint for the given lock mode to
  1584.      * @param int    $lockMode   One of the Doctrine\DBAL\LockMode::* constants
  1585.      * @psalm-param LockMode::* $lockMode
  1586.      */
  1587.     public function appendLockHint(string $fromClauseint $lockMode): string
  1588.     {
  1589.         switch ($lockMode) {
  1590.             case LockMode::NONE:
  1591.             case LockMode::OPTIMISTIC:
  1592.             case LockMode::PESSIMISTIC_READ:
  1593.             case LockMode::PESSIMISTIC_WRITE:
  1594.                 return $fromClause;
  1595.             default:
  1596.                 throw InvalidLockMode::fromLockMode($lockMode);
  1597.         }
  1598.     }
  1599.     /**
  1600.      * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock.
  1601.      *
  1602.      * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
  1603.      * vendors allow to lighten this constraint up to be a real read lock.
  1604.      *
  1605.      * @return string
  1606.      */
  1607.     public function getReadLockSQL()
  1608.     {
  1609.         return $this->getForUpdateSQL();
  1610.     }
  1611.     /**
  1612.      * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
  1613.      *
  1614.      * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard.
  1615.      *
  1616.      * @return string
  1617.      */
  1618.     public function getWriteLockSQL()
  1619.     {
  1620.         return $this->getForUpdateSQL();
  1621.     }
  1622.     /**
  1623.      * Returns the SQL snippet to drop an existing table.
  1624.      *
  1625.      * @param Table|string $table
  1626.      *
  1627.      * @return string
  1628.      *
  1629.      * @throws InvalidArgumentException
  1630.      */
  1631.     public function getDropTableSQL($table)
  1632.     {
  1633.         $tableArg $table;
  1634.         if ($table instanceof Table) {
  1635.             Deprecation::trigger(
  1636.                 'doctrine/dbal',
  1637.                 'https://github.com/doctrine/dbal/issues/4798',
  1638.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  1639.                 __METHOD__,
  1640.             );
  1641.             $table $table->getQuotedName($this);
  1642.         }
  1643.         if (! is_string($table)) {
  1644.             throw new InvalidArgumentException(
  1645.                 __METHOD__ '() expects $table parameter to be string or ' Table::class . '.',
  1646.             );
  1647.         }
  1648.         if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) {
  1649.             Deprecation::trigger(
  1650.                 'doctrine/dbal',
  1651.                 'https://github.com/doctrine/dbal/issues/5784',
  1652.                 'Subscribing to %s events is deprecated.',
  1653.                 Events::onSchemaDropTable,
  1654.             );
  1655.             $eventArgs = new SchemaDropTableEventArgs($tableArg$this);
  1656.             $this->_eventManager->dispatchEvent(Events::onSchemaDropTable$eventArgs);
  1657.             if ($eventArgs->isDefaultPrevented()) {
  1658.                 $sql $eventArgs->getSql();
  1659.                 if ($sql === null) {
  1660.                     throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL');
  1661.                 }
  1662.                 return $sql;
  1663.             }
  1664.         }
  1665.         return 'DROP TABLE ' $table;
  1666.     }
  1667.     /**
  1668.      * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
  1669.      *
  1670.      * @param Table|string $table
  1671.      *
  1672.      * @return string
  1673.      */
  1674.     public function getDropTemporaryTableSQL($table)
  1675.     {
  1676.         if ($table instanceof Table) {
  1677.             Deprecation::trigger(
  1678.                 'doctrine/dbal',
  1679.                 'https://github.com/doctrine/dbal/issues/4798',
  1680.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  1681.                 __METHOD__,
  1682.             );
  1683.             $table $table->getQuotedName($this);
  1684.         }
  1685.         return $this->getDropTableSQL($table);
  1686.     }
  1687.     /**
  1688.      * Returns the SQL to drop an index from a table.
  1689.      *
  1690.      * @param Index|string      $index
  1691.      * @param Table|string|null $table
  1692.      *
  1693.      * @return string
  1694.      *
  1695.      * @throws InvalidArgumentException
  1696.      */
  1697.     public function getDropIndexSQL($index$table null)
  1698.     {
  1699.         if ($index instanceof Index) {
  1700.             Deprecation::trigger(
  1701.                 'doctrine/dbal',
  1702.                 'https://github.com/doctrine/dbal/issues/4798',
  1703.                 'Passing $index as an Index object to %s is deprecated. Pass it as a quoted name instead.',
  1704.                 __METHOD__,
  1705.             );
  1706.             $index $index->getQuotedName($this);
  1707.         } elseif (! is_string($index)) {
  1708.             throw new InvalidArgumentException(
  1709.                 __METHOD__ '() expects $index parameter to be string or ' Index::class . '.',
  1710.             );
  1711.         }
  1712.         return 'DROP INDEX ' $index;
  1713.     }
  1714.     /**
  1715.      * Returns the SQL to drop a constraint.
  1716.      *
  1717.      * @internal The method should be only used from within the {@see AbstractPlatform} class hierarchy.
  1718.      *
  1719.      * @param Constraint|string $constraint
  1720.      * @param Table|string      $table
  1721.      *
  1722.      * @return string
  1723.      */
  1724.     public function getDropConstraintSQL($constraint$table)
  1725.     {
  1726.         if ($constraint instanceof Constraint) {
  1727.             Deprecation::trigger(
  1728.                 'doctrine/dbal',
  1729.                 'https://github.com/doctrine/dbal/issues/4798',
  1730.                 'Passing $constraint as a Constraint object to %s is deprecated. Pass it as a quoted name instead.',
  1731.                 __METHOD__,
  1732.             );
  1733.         } else {
  1734.             $constraint = new Identifier($constraint);
  1735.         }
  1736.         if ($table instanceof Table) {
  1737.             Deprecation::trigger(
  1738.                 'doctrine/dbal',
  1739.                 'https://github.com/doctrine/dbal/issues/4798',
  1740.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  1741.                 __METHOD__,
  1742.             );
  1743.         } else {
  1744.             $table = new Identifier($table);
  1745.         }
  1746.         $constraint $constraint->getQuotedName($this);
  1747.         $table      $table->getQuotedName($this);
  1748.         return 'ALTER TABLE ' $table ' DROP CONSTRAINT ' $constraint;
  1749.     }
  1750.     /**
  1751.      * Returns the SQL to drop a foreign key.
  1752.      *
  1753.      * @param ForeignKeyConstraint|string $foreignKey
  1754.      * @param Table|string                $table
  1755.      *
  1756.      * @return string
  1757.      */
  1758.     public function getDropForeignKeySQL($foreignKey$table)
  1759.     {
  1760.         if ($foreignKey instanceof ForeignKeyConstraint) {
  1761.             Deprecation::trigger(
  1762.                 'doctrine/dbal',
  1763.                 'https://github.com/doctrine/dbal/issues/4798',
  1764.                 'Passing $foreignKey as a ForeignKeyConstraint object to %s is deprecated.'
  1765.                     ' Pass it as a quoted name instead.',
  1766.                 __METHOD__,
  1767.             );
  1768.         } else {
  1769.             $foreignKey = new Identifier($foreignKey);
  1770.         }
  1771.         if ($table instanceof Table) {
  1772.             Deprecation::trigger(
  1773.                 'doctrine/dbal',
  1774.                 'https://github.com/doctrine/dbal/issues/4798',
  1775.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  1776.                 __METHOD__,
  1777.             );
  1778.         } else {
  1779.             $table = new Identifier($table);
  1780.         }
  1781.         $foreignKey $foreignKey->getQuotedName($this);
  1782.         $table      $table->getQuotedName($this);
  1783.         return 'ALTER TABLE ' $table ' DROP FOREIGN KEY ' $foreignKey;
  1784.     }
  1785.     /**
  1786.      * Returns the SQL to drop a unique constraint.
  1787.      */
  1788.     public function getDropUniqueConstraintSQL(string $namestring $tableName): string
  1789.     {
  1790.         return $this->getDropConstraintSQL($name$tableName);
  1791.     }
  1792.     /**
  1793.      * Returns the SQL statement(s) to create a table with the specified name, columns and constraints
  1794.      * on this platform.
  1795.      *
  1796.      * @param int $createFlags
  1797.      * @psalm-param int-mask-of<self::CREATE_*> $createFlags
  1798.      *
  1799.      * @return list<string> The list of SQL statements.
  1800.      *
  1801.      * @throws Exception
  1802.      * @throws InvalidArgumentException
  1803.      */
  1804.     public function getCreateTableSQL(Table $table$createFlags self::CREATE_INDEXES)
  1805.     {
  1806.         if (! is_int($createFlags)) {
  1807.             throw new InvalidArgumentException(
  1808.                 'Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.',
  1809.             );
  1810.         }
  1811.         if (($createFlags self::CREATE_INDEXES) === 0) {
  1812.             Deprecation::trigger(
  1813.                 'doctrine/dbal',
  1814.                 'https://github.com/doctrine/dbal/pull/5416',
  1815.                 'Unsetting the CREATE_INDEXES flag in AbstractPlatform::getCreateTableSQL() is deprecated.',
  1816.             );
  1817.         }
  1818.         if (($createFlags self::CREATE_FOREIGNKEYS) === 0) {
  1819.             Deprecation::trigger(
  1820.                 'doctrine/dbal',
  1821.                 'https://github.com/doctrine/dbal/pull/5416',
  1822.                 'Not setting the CREATE_FOREIGNKEYS flag in AbstractPlatform::getCreateTableSQL()'
  1823.                     ' is deprecated. In order to build the statements that create multiple tables'
  1824.                     ' referencing each other via foreign keys, use AbstractPlatform::getCreateTablesSQL().',
  1825.             );
  1826.         }
  1827.         return $this->buildCreateTableSQL(
  1828.             $table,
  1829.             ($createFlags self::CREATE_INDEXES) > 0,
  1830.             ($createFlags self::CREATE_FOREIGNKEYS) > 0,
  1831.         );
  1832.     }
  1833.     /**
  1834.      * @internal
  1835.      *
  1836.      * @return list<string>
  1837.      *
  1838.      * @throws Exception
  1839.      */
  1840.     final protected function getCreateTableWithoutForeignKeysSQL(Table $table): array
  1841.     {
  1842.         return $this->buildCreateTableSQL($tabletruefalse);
  1843.     }
  1844.     /**
  1845.      * @return list<string>
  1846.      *
  1847.      * @throws Exception
  1848.      */
  1849.     private function buildCreateTableSQL(Table $tablebool $createIndexesbool $createForeignKeys): array
  1850.     {
  1851.         if (count($table->getColumns()) === 0) {
  1852.             throw Exception::noColumnsSpecifiedForTable($table->getName());
  1853.         }
  1854.         $tableName                    $table->getQuotedName($this);
  1855.         $options                      $table->getOptions();
  1856.         $options['uniqueConstraints'] = [];
  1857.         $options['indexes']           = [];
  1858.         $options['primary']           = [];
  1859.         if ($createIndexes) {
  1860.             foreach ($table->getIndexes() as $index) {
  1861.                 if (! $index->isPrimary()) {
  1862.                     $options['indexes'][$index->getQuotedName($this)] = $index;
  1863.                     continue;
  1864.                 }
  1865.                 $options['primary']       = $index->getQuotedColumns($this);
  1866.                 $options['primary_index'] = $index;
  1867.             }
  1868.             foreach ($table->getUniqueConstraints() as $uniqueConstraint) {
  1869.                 $options['uniqueConstraints'][$uniqueConstraint->getQuotedName($this)] = $uniqueConstraint;
  1870.             }
  1871.         }
  1872.         if ($createForeignKeys) {
  1873.             $options['foreignKeys'] = [];
  1874.             foreach ($table->getForeignKeys() as $fkConstraint) {
  1875.                 $options['foreignKeys'][] = $fkConstraint;
  1876.             }
  1877.         }
  1878.         $columnSql = [];
  1879.         $columns   = [];
  1880.         foreach ($table->getColumns() as $column) {
  1881.             if (
  1882.                 $this->_eventManager !== null
  1883.                 && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)
  1884.             ) {
  1885.                 Deprecation::trigger(
  1886.                     'doctrine/dbal',
  1887.                     'https://github.com/doctrine/dbal/issues/5784',
  1888.                     'Subscribing to %s events is deprecated.',
  1889.                     Events::onSchemaCreateTableColumn,
  1890.                 );
  1891.                 $eventArgs = new SchemaCreateTableColumnEventArgs($column$table$this);
  1892.                 $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn$eventArgs);
  1893.                 $columnSql array_merge($columnSql$eventArgs->getSql());
  1894.                 if ($eventArgs->isDefaultPrevented()) {
  1895.                     continue;
  1896.                 }
  1897.             }
  1898.             $columnData $this->columnToArray($column);
  1899.             if (in_array($column->getName(), $options['primary'], true)) {
  1900.                 $columnData['primary'] = true;
  1901.             }
  1902.             $columns[$columnData['name']] = $columnData;
  1903.         }
  1904.         if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
  1905.             Deprecation::trigger(
  1906.                 'doctrine/dbal',
  1907.                 'https://github.com/doctrine/dbal/issues/5784',
  1908.                 'Subscribing to %s events is deprecated.',
  1909.                 Events::onSchemaCreateTable,
  1910.             );
  1911.             $eventArgs = new SchemaCreateTableEventArgs($table$columns$options$this);
  1912.             $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable$eventArgs);
  1913.             if ($eventArgs->isDefaultPrevented()) {
  1914.                 return array_merge($eventArgs->getSql(), $columnSql);
  1915.             }
  1916.         }
  1917.         $sql $this->_getCreateTableSQL($tableName$columns$options);
  1918.         if ($this->supportsCommentOnStatement()) {
  1919.             if ($table->hasOption('comment')) {
  1920.                 $sql[] = $this->getCommentOnTableSQL($tableName$table->getOption('comment'));
  1921.             }
  1922.             foreach ($table->getColumns() as $column) {
  1923.                 $comment $this->getColumnComment($column);
  1924.                 if ($comment === null || $comment === '') {
  1925.                     continue;
  1926.                 }
  1927.                 $sql[] = $this->getCommentOnColumnSQL($tableName$column->getQuotedName($this), $comment);
  1928.             }
  1929.         }
  1930.         return array_merge($sql$columnSql);
  1931.     }
  1932.     /**
  1933.      * @param list<Table> $tables
  1934.      *
  1935.      * @return list<string>
  1936.      *
  1937.      * @throws Exception
  1938.      */
  1939.     public function getCreateTablesSQL(array $tables): array
  1940.     {
  1941.         $sql = [];
  1942.         foreach ($tables as $table) {
  1943.             $sql array_merge($sql$this->getCreateTableWithoutForeignKeysSQL($table));
  1944.         }
  1945.         foreach ($tables as $table) {
  1946.             foreach ($table->getForeignKeys() as $foreignKey) {
  1947.                 $sql[] = $this->getCreateForeignKeySQL(
  1948.                     $foreignKey,
  1949.                     $table->getQuotedName($this),
  1950.                 );
  1951.             }
  1952.         }
  1953.         return $sql;
  1954.     }
  1955.     /**
  1956.      * @param list<Table> $tables
  1957.      *
  1958.      * @return list<string>
  1959.      */
  1960.     public function getDropTablesSQL(array $tables): array
  1961.     {
  1962.         $sql = [];
  1963.         foreach ($tables as $table) {
  1964.             foreach ($table->getForeignKeys() as $foreignKey) {
  1965.                 $sql[] = $this->getDropForeignKeySQL(
  1966.                     $foreignKey->getQuotedName($this),
  1967.                     $table->getQuotedName($this),
  1968.                 );
  1969.             }
  1970.         }
  1971.         foreach ($tables as $table) {
  1972.             $sql[] = $this->getDropTableSQL($table->getQuotedName($this));
  1973.         }
  1974.         return $sql;
  1975.     }
  1976.     protected function getCommentOnTableSQL(string $tableName, ?string $comment): string
  1977.     {
  1978.         $tableName = new Identifier($tableName);
  1979.         return sprintf(
  1980.             'COMMENT ON TABLE %s IS %s',
  1981.             $tableName->getQuotedName($this),
  1982.             $this->quoteStringLiteral((string) $comment),
  1983.         );
  1984.     }
  1985.     /**
  1986.      * @param string      $tableName
  1987.      * @param string      $columnName
  1988.      * @param string|null $comment
  1989.      *
  1990.      * @return string
  1991.      */
  1992.     public function getCommentOnColumnSQL($tableName$columnName$comment)
  1993.     {
  1994.         $tableName  = new Identifier($tableName);
  1995.         $columnName = new Identifier($columnName);
  1996.         return sprintf(
  1997.             'COMMENT ON COLUMN %s.%s IS %s',
  1998.             $tableName->getQuotedName($this),
  1999.             $columnName->getQuotedName($this),
  2000.             $this->quoteStringLiteral((string) $comment),
  2001.         );
  2002.     }
  2003.     /**
  2004.      * Returns the SQL to create inline comment on a column.
  2005.      *
  2006.      * @param string $comment
  2007.      *
  2008.      * @return string
  2009.      *
  2010.      * @throws Exception If not supported on this platform.
  2011.      */
  2012.     public function getInlineColumnCommentSQL($comment)
  2013.     {
  2014.         if (! $this->supportsInlineColumnComments()) {
  2015.             throw Exception::notSupported(__METHOD__);
  2016.         }
  2017.         return 'COMMENT ' $this->quoteStringLiteral($comment);
  2018.     }
  2019.     /**
  2020.      * Returns the SQL used to create a table.
  2021.      *
  2022.      * @param string    $name
  2023.      * @param mixed[][] $columns
  2024.      * @param mixed[]   $options
  2025.      *
  2026.      * @return string[]
  2027.      */
  2028.     protected function _getCreateTableSQL($name, array $columns, array $options = [])
  2029.     {
  2030.         $columnListSql $this->getColumnDeclarationListSQL($columns);
  2031.         if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
  2032.             foreach ($options['uniqueConstraints'] as $index => $definition) {
  2033.                 $columnListSql .= ', ' $this->getUniqueConstraintDeclarationSQL($index$definition);
  2034.             }
  2035.         }
  2036.         if (isset($options['primary']) && ! empty($options['primary'])) {
  2037.             $columnListSql .= ', PRIMARY KEY(' implode(', 'array_unique(array_values($options['primary']))) . ')';
  2038.         }
  2039.         if (isset($options['indexes']) && ! empty($options['indexes'])) {
  2040.             foreach ($options['indexes'] as $index => $definition) {
  2041.                 $columnListSql .= ', ' $this->getIndexDeclarationSQL($index$definition);
  2042.             }
  2043.         }
  2044.         $query 'CREATE TABLE ' $name ' (' $columnListSql;
  2045.         $check $this->getCheckDeclarationSQL($columns);
  2046.         if (! empty($check)) {
  2047.             $query .= ', ' $check;
  2048.         }
  2049.         $query .= ')';
  2050.         $sql = [$query];
  2051.         if (isset($options['foreignKeys'])) {
  2052.             foreach ($options['foreignKeys'] as $definition) {
  2053.                 $sql[] = $this->getCreateForeignKeySQL($definition$name);
  2054.             }
  2055.         }
  2056.         return $sql;
  2057.     }
  2058.     /** @return string */
  2059.     public function getCreateTemporaryTableSnippetSQL()
  2060.     {
  2061.         return 'CREATE TEMPORARY TABLE';
  2062.     }
  2063.     /**
  2064.      * Generates SQL statements that can be used to apply the diff.
  2065.      *
  2066.      * @return list<string>
  2067.      */
  2068.     public function getAlterSchemaSQL(SchemaDiff $diff): array
  2069.     {
  2070.         return $diff->toSql($this);
  2071.     }
  2072.     /**
  2073.      * Returns the SQL to create a sequence on this platform.
  2074.      *
  2075.      * @return string
  2076.      *
  2077.      * @throws Exception If not supported on this platform.
  2078.      */
  2079.     public function getCreateSequenceSQL(Sequence $sequence)
  2080.     {
  2081.         throw Exception::notSupported(__METHOD__);
  2082.     }
  2083.     /**
  2084.      * Returns the SQL to change a sequence on this platform.
  2085.      *
  2086.      * @return string
  2087.      *
  2088.      * @throws Exception If not supported on this platform.
  2089.      */
  2090.     public function getAlterSequenceSQL(Sequence $sequence)
  2091.     {
  2092.         throw Exception::notSupported(__METHOD__);
  2093.     }
  2094.     /**
  2095.      * Returns the SQL snippet to drop an existing sequence.
  2096.      *
  2097.      * @param Sequence|string $sequence
  2098.      *
  2099.      * @return string
  2100.      *
  2101.      * @throws Exception If not supported on this platform.
  2102.      */
  2103.     public function getDropSequenceSQL($sequence)
  2104.     {
  2105.         if (! $this->supportsSequences()) {
  2106.             throw Exception::notSupported(__METHOD__);
  2107.         }
  2108.         if ($sequence instanceof Sequence) {
  2109.             Deprecation::trigger(
  2110.                 'doctrine/dbal',
  2111.                 'https://github.com/doctrine/dbal/issues/4798',
  2112.                 'Passing $sequence as a Sequence object to %s is deprecated. Pass it as a quoted name instead.',
  2113.                 __METHOD__,
  2114.             );
  2115.             $sequence $sequence->getQuotedName($this);
  2116.         }
  2117.         return 'DROP SEQUENCE ' $sequence;
  2118.     }
  2119.     /**
  2120.      * Returns the SQL to create a constraint on a table on this platform.
  2121.      *
  2122.      * @deprecated Use {@see getCreateIndexSQL()}, {@see getCreateForeignKeySQL()}
  2123.      *             or {@see getCreateUniqueConstraintSQL()} instead.
  2124.      *
  2125.      * @param Table|string $table
  2126.      *
  2127.      * @return string
  2128.      *
  2129.      * @throws InvalidArgumentException
  2130.      */
  2131.     public function getCreateConstraintSQL(Constraint $constraint$table)
  2132.     {
  2133.         if ($table instanceof Table) {
  2134.             Deprecation::trigger(
  2135.                 'doctrine/dbal',
  2136.                 'https://github.com/doctrine/dbal/issues/4798',
  2137.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  2138.                 __METHOD__,
  2139.             );
  2140.             $table $table->getQuotedName($this);
  2141.         }
  2142.         $query 'ALTER TABLE ' $table ' ADD CONSTRAINT ' $constraint->getQuotedName($this);
  2143.         $columnList '(' implode(', '$constraint->getQuotedColumns($this)) . ')';
  2144.         $referencesClause '';
  2145.         if ($constraint instanceof Index) {
  2146.             if ($constraint->isPrimary()) {
  2147.                 $query .= ' PRIMARY KEY';
  2148.             } elseif ($constraint->isUnique()) {
  2149.                 $query .= ' UNIQUE';
  2150.             } else {
  2151.                 throw new InvalidArgumentException(
  2152.                     'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().',
  2153.                 );
  2154.             }
  2155.         } elseif ($constraint instanceof UniqueConstraint) {
  2156.             $query .= ' UNIQUE';
  2157.         } elseif ($constraint instanceof ForeignKeyConstraint) {
  2158.             $query .= ' FOREIGN KEY';
  2159.             $referencesClause ' REFERENCES ' $constraint->getQuotedForeignTableName($this) .
  2160.                 ' (' implode(', '$constraint->getQuotedForeignColumns($this)) . ')';
  2161.         }
  2162.         $query .= ' ' $columnList $referencesClause;
  2163.         return $query;
  2164.     }
  2165.     /**
  2166.      * Returns the SQL to create an index on a table on this platform.
  2167.      *
  2168.      * @param Table|string $table The name of the table on which the index is to be created.
  2169.      *
  2170.      * @return string
  2171.      *
  2172.      * @throws InvalidArgumentException
  2173.      */
  2174.     public function getCreateIndexSQL(Index $index$table)
  2175.     {
  2176.         if ($table instanceof Table) {
  2177.             Deprecation::trigger(
  2178.                 'doctrine/dbal',
  2179.                 'https://github.com/doctrine/dbal/issues/4798',
  2180.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  2181.                 __METHOD__,
  2182.             );
  2183.             $table $table->getQuotedName($this);
  2184.         }
  2185.         $name    $index->getQuotedName($this);
  2186.         $columns $index->getColumns();
  2187.         if (count($columns) === 0) {
  2188.             throw new InvalidArgumentException(sprintf(
  2189.                 'Incomplete or invalid index definition %s on table %s',
  2190.                 $name,
  2191.                 $table,
  2192.             ));
  2193.         }
  2194.         if ($index->isPrimary()) {
  2195.             return $this->getCreatePrimaryKeySQL($index$table);
  2196.         }
  2197.         $query  'CREATE ' $this->getCreateIndexSQLFlags($index) . 'INDEX ' $name ' ON ' $table;
  2198.         $query .= ' (' $this->getIndexFieldDeclarationListSQL($index) . ')' $this->getPartialIndexSQL($index);
  2199.         return $query;
  2200.     }
  2201.     /**
  2202.      * Adds condition for partial index.
  2203.      *
  2204.      * @return string
  2205.      */
  2206.     protected function getPartialIndexSQL(Index $index)
  2207.     {
  2208.         if ($this->supportsPartialIndexes() && $index->hasOption('where')) {
  2209.             return ' WHERE ' $index->getOption('where');
  2210.         }
  2211.         return '';
  2212.     }
  2213.     /**
  2214.      * Adds additional flags for index generation.
  2215.      *
  2216.      * @return string
  2217.      */
  2218.     protected function getCreateIndexSQLFlags(Index $index)
  2219.     {
  2220.         return $index->isUnique() ? 'UNIQUE ' '';
  2221.     }
  2222.     /**
  2223.      * Returns the SQL to create an unnamed primary key constraint.
  2224.      *
  2225.      * @param Table|string $table
  2226.      *
  2227.      * @return string
  2228.      */
  2229.     public function getCreatePrimaryKeySQL(Index $index$table)
  2230.     {
  2231.         if ($table instanceof Table) {
  2232.             Deprecation::trigger(
  2233.                 'doctrine/dbal',
  2234.                 'https://github.com/doctrine/dbal/issues/4798',
  2235.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  2236.                 __METHOD__,
  2237.             );
  2238.             $table $table->getQuotedName($this);
  2239.         }
  2240.         return 'ALTER TABLE ' $table ' ADD PRIMARY KEY (' $this->getIndexFieldDeclarationListSQL($index) . ')';
  2241.     }
  2242.     /**
  2243.      * Returns the SQL to create a named schema.
  2244.      *
  2245.      * @param string $schemaName
  2246.      *
  2247.      * @return string
  2248.      *
  2249.      * @throws Exception If not supported on this platform.
  2250.      */
  2251.     public function getCreateSchemaSQL($schemaName)
  2252.     {
  2253.         if (! $this->supportsSchemas()) {
  2254.             throw Exception::notSupported(__METHOD__);
  2255.         }
  2256.         return 'CREATE SCHEMA ' $schemaName;
  2257.     }
  2258.     /**
  2259.      * Returns the SQL to create a unique constraint on a table on this platform.
  2260.      */
  2261.     public function getCreateUniqueConstraintSQL(UniqueConstraint $constraintstring $tableName): string
  2262.     {
  2263.         return $this->getCreateConstraintSQL($constraint$tableName);
  2264.     }
  2265.     /**
  2266.      * Returns the SQL snippet to drop a schema.
  2267.      *
  2268.      * @throws Exception If not supported on this platform.
  2269.      */
  2270.     public function getDropSchemaSQL(string $schemaName): string
  2271.     {
  2272.         if (! $this->supportsSchemas()) {
  2273.             throw Exception::notSupported(__METHOD__);
  2274.         }
  2275.         return 'DROP SCHEMA ' $schemaName;
  2276.     }
  2277.     /**
  2278.      * Quotes a string so that it can be safely used as a table or column name,
  2279.      * even if it is a reserved word of the platform. This also detects identifier
  2280.      * chains separated by dot and quotes them independently.
  2281.      *
  2282.      * NOTE: Just because you CAN use quoted identifiers doesn't mean
  2283.      * you SHOULD use them. In general, they end up causing way more
  2284.      * problems than they solve.
  2285.      *
  2286.      * @param string $str The identifier name to be quoted.
  2287.      *
  2288.      * @return string The quoted identifier string.
  2289.      */
  2290.     public function quoteIdentifier($str)
  2291.     {
  2292.         if (strpos($str'.') !== false) {
  2293.             $parts array_map([$this'quoteSingleIdentifier'], explode('.'$str));
  2294.             return implode('.'$parts);
  2295.         }
  2296.         return $this->quoteSingleIdentifier($str);
  2297.     }
  2298.     /**
  2299.      * Quotes a single identifier (no dot chain separation).
  2300.      *
  2301.      * @param string $str The identifier name to be quoted.
  2302.      *
  2303.      * @return string The quoted identifier string.
  2304.      */
  2305.     public function quoteSingleIdentifier($str)
  2306.     {
  2307.         $c $this->getIdentifierQuoteCharacter();
  2308.         return $c str_replace($c$c $c$str) . $c;
  2309.     }
  2310.     /**
  2311.      * Returns the SQL to create a new foreign key.
  2312.      *
  2313.      * @param ForeignKeyConstraint $foreignKey The foreign key constraint.
  2314.      * @param Table|string         $table      The name of the table on which the foreign key is to be created.
  2315.      *
  2316.      * @return string
  2317.      */
  2318.     public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey$table)
  2319.     {
  2320.         if ($table instanceof Table) {
  2321.             Deprecation::trigger(
  2322.                 'doctrine/dbal',
  2323.                 'https://github.com/doctrine/dbal/issues/4798',
  2324.                 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  2325.                 __METHOD__,
  2326.             );
  2327.             $table $table->getQuotedName($this);
  2328.         }
  2329.         return 'ALTER TABLE ' $table ' ADD ' $this->getForeignKeyDeclarationSQL($foreignKey);
  2330.     }
  2331.     /**
  2332.      * Gets the SQL statements for altering an existing table.
  2333.      *
  2334.      * This method returns an array of SQL statements, since some platforms need several statements.
  2335.      *
  2336.      * @return list<string>
  2337.      *
  2338.      * @throws Exception If not supported on this platform.
  2339.      */
  2340.     public function getAlterTableSQL(TableDiff $diff)
  2341.     {
  2342.         throw Exception::notSupported(__METHOD__);
  2343.     }
  2344.     /** @return list<string> */
  2345.     public function getRenameTableSQL(string $oldNamestring $newName): array
  2346.     {
  2347.         return [
  2348.             sprintf('ALTER TABLE %s RENAME TO %s'$oldName$newName),
  2349.         ];
  2350.     }
  2351.     /**
  2352.      * @param mixed[] $columnSql
  2353.      *
  2354.      * @return bool
  2355.      */
  2356.     protected function onSchemaAlterTableAddColumn(Column $columnTableDiff $diff, &$columnSql)
  2357.     {
  2358.         if ($this->_eventManager === null) {
  2359.             return false;
  2360.         }
  2361.         if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) {
  2362.             return false;
  2363.         }
  2364.         Deprecation::trigger(
  2365.             'doctrine/dbal',
  2366.             'https://github.com/doctrine/dbal/issues/5784',
  2367.             'Subscribing to %s events is deprecated.',
  2368.             Events::onSchemaAlterTableAddColumn,
  2369.         );
  2370.         $eventArgs = new SchemaAlterTableAddColumnEventArgs($column$diff$this);
  2371.         $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn$eventArgs);
  2372.         $columnSql array_merge($columnSql$eventArgs->getSql());
  2373.         return $eventArgs->isDefaultPrevented();
  2374.     }
  2375.     /**
  2376.      * @param string[] $columnSql
  2377.      *
  2378.      * @return bool
  2379.      */
  2380.     protected function onSchemaAlterTableRemoveColumn(Column $columnTableDiff $diff, &$columnSql)
  2381.     {
  2382.         if ($this->_eventManager === null) {
  2383.             return false;
  2384.         }
  2385.         if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) {
  2386.             return false;
  2387.         }
  2388.         Deprecation::trigger(
  2389.             'doctrine/dbal',
  2390.             'https://github.com/doctrine/dbal/issues/5784',
  2391.             'Subscribing to %s events is deprecated.',
  2392.             Events::onSchemaAlterTableRemoveColumn,
  2393.         );
  2394.         $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column$diff$this);
  2395.         $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn$eventArgs);
  2396.         $columnSql array_merge($columnSql$eventArgs->getSql());
  2397.         return $eventArgs->isDefaultPrevented();
  2398.     }
  2399.     /**
  2400.      * @param string[] $columnSql
  2401.      *
  2402.      * @return bool
  2403.      */
  2404.     protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiffTableDiff $diff, &$columnSql)
  2405.     {
  2406.         if ($this->_eventManager === null) {
  2407.             return false;
  2408.         }
  2409.         if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) {
  2410.             return false;
  2411.         }
  2412.         Deprecation::trigger(
  2413.             'doctrine/dbal',
  2414.             'https://github.com/doctrine/dbal/issues/5784',
  2415.             'Subscribing to %s events is deprecated.',
  2416.             Events::onSchemaAlterTableChangeColumn,
  2417.         );
  2418.         $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff$diff$this);
  2419.         $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn$eventArgs);
  2420.         $columnSql array_merge($columnSql$eventArgs->getSql());
  2421.         return $eventArgs->isDefaultPrevented();
  2422.     }
  2423.     /**
  2424.      * @param string   $oldColumnName
  2425.      * @param string[] $columnSql
  2426.      *
  2427.      * @return bool
  2428.      */
  2429.     protected function onSchemaAlterTableRenameColumn($oldColumnNameColumn $columnTableDiff $diff, &$columnSql)
  2430.     {
  2431.         if ($this->_eventManager === null) {
  2432.             return false;
  2433.         }
  2434.         if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) {
  2435.             return false;
  2436.         }
  2437.         Deprecation::trigger(
  2438.             'doctrine/dbal',
  2439.             'https://github.com/doctrine/dbal/issues/5784',
  2440.             'Subscribing to %s events is deprecated.',
  2441.             Events::onSchemaAlterTableRenameColumn,
  2442.         );
  2443.         $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName$column$diff$this);
  2444.         $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn$eventArgs);
  2445.         $columnSql array_merge($columnSql$eventArgs->getSql());
  2446.         return $eventArgs->isDefaultPrevented();
  2447.     }
  2448.     /**
  2449.      * @param string[] $sql
  2450.      *
  2451.      * @return bool
  2452.      */
  2453.     protected function onSchemaAlterTable(TableDiff $diff, &$sql)
  2454.     {
  2455.         if ($this->_eventManager === null) {
  2456.             return false;
  2457.         }
  2458.         if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) {
  2459.             return false;
  2460.         }
  2461.         Deprecation::trigger(
  2462.             'doctrine/dbal',
  2463.             'https://github.com/doctrine/dbal/issues/5784',
  2464.             'Subscribing to %s events is deprecated.',
  2465.             Events::onSchemaAlterTable,
  2466.         );
  2467.         $eventArgs = new SchemaAlterTableEventArgs($diff$this);
  2468.         $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable$eventArgs);
  2469.         $sql array_merge($sql$eventArgs->getSql());
  2470.         return $eventArgs->isDefaultPrevented();
  2471.     }
  2472.     /** @return string[] */
  2473.     protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
  2474.     {
  2475.         $tableNameSQL = ($diff->getOldTable() ?? $diff->getName($this))->getQuotedName($this);
  2476.         $sql = [];
  2477.         if ($this->supportsForeignKeyConstraints()) {
  2478.             foreach ($diff->getDroppedForeignKeys() as $foreignKey) {
  2479.                 if ($foreignKey instanceof ForeignKeyConstraint) {
  2480.                     $foreignKey $foreignKey->getQuotedName($this);
  2481.                 }
  2482.                 $sql[] = $this->getDropForeignKeySQL($foreignKey$tableNameSQL);
  2483.             }
  2484.             foreach ($diff->getModifiedForeignKeys() as $foreignKey) {
  2485.                 $sql[] = $this->getDropForeignKeySQL($foreignKey->getQuotedName($this), $tableNameSQL);
  2486.             }
  2487.         }
  2488.         foreach ($diff->getDroppedIndexes() as $index) {
  2489.             $sql[] = $this->getDropIndexSQL($index->getQuotedName($this), $tableNameSQL);
  2490.         }
  2491.         foreach ($diff->getModifiedIndexes() as $index) {
  2492.             $sql[] = $this->getDropIndexSQL($index->getQuotedName($this), $tableNameSQL);
  2493.         }
  2494.         return $sql;
  2495.     }
  2496.     /** @return string[] */
  2497.     protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff)
  2498.     {
  2499.         $sql     = [];
  2500.         $newName $diff->getNewName();
  2501.         if ($newName !== false) {
  2502.             $tableNameSQL $newName->getQuotedName($this);
  2503.         } else {
  2504.             $tableNameSQL = ($diff->getOldTable() ?? $diff->getName($this))->getQuotedName($this);
  2505.         }
  2506.         if ($this->supportsForeignKeyConstraints()) {
  2507.             foreach ($diff->getAddedForeignKeys() as $foreignKey) {
  2508.                 $sql[] = $this->getCreateForeignKeySQL($foreignKey$tableNameSQL);
  2509.             }
  2510.             foreach ($diff->getModifiedForeignKeys() as $foreignKey) {
  2511.                 $sql[] = $this->getCreateForeignKeySQL($foreignKey$tableNameSQL);
  2512.             }
  2513.         }
  2514.         foreach ($diff->getAddedIndexes() as $index) {
  2515.             $sql[] = $this->getCreateIndexSQL($index$tableNameSQL);
  2516.         }
  2517.         foreach ($diff->getModifiedIndexes() as $index) {
  2518.             $sql[] = $this->getCreateIndexSQL($index$tableNameSQL);
  2519.         }
  2520.         foreach ($diff->getRenamedIndexes() as $oldIndexName => $index) {
  2521.             $oldIndexName = new Identifier($oldIndexName);
  2522.             $sql          array_merge(
  2523.                 $sql,
  2524.                 $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index$tableNameSQL),
  2525.             );
  2526.         }
  2527.         return $sql;
  2528.     }
  2529.     /**
  2530.      * Returns the SQL for renaming an index on a table.
  2531.      *
  2532.      * @param string $oldIndexName The name of the index to rename from.
  2533.      * @param Index  $index        The definition of the index to rename to.
  2534.      * @param string $tableName    The table to rename the given index on.
  2535.      *
  2536.      * @return string[] The sequence of SQL statements for renaming the given index.
  2537.      */
  2538.     protected function getRenameIndexSQL($oldIndexNameIndex $index$tableName)
  2539.     {
  2540.         return [
  2541.             $this->getDropIndexSQL($oldIndexName$tableName),
  2542.             $this->getCreateIndexSQL($index$tableName),
  2543.         ];
  2544.     }
  2545.     /**
  2546.      * Gets declaration of a number of columns in bulk.
  2547.      *
  2548.      * @param mixed[][] $columns A multidimensional associative array.
  2549.      *                           The first dimension determines the column name, while the second
  2550.      *                           dimension is keyed with the name of the properties
  2551.      *                           of the column being declared as array indexes. Currently, the types
  2552.      *                           of supported column properties are as follows:
  2553.      *
  2554.      *      length
  2555.      *          Integer value that determines the maximum length of the text
  2556.      *          column. If this argument is missing the column should be
  2557.      *          declared to have the longest length allowed by the DBMS.
  2558.      *
  2559.      *      default
  2560.      *          Text value to be used as default for this column.
  2561.      *
  2562.      *      notnull
  2563.      *          Boolean flag that indicates whether this column is constrained
  2564.      *          to not be set to null.
  2565.      *      charset
  2566.      *          Text value with the default CHARACTER SET for this column.
  2567.      *      collation
  2568.      *          Text value with the default COLLATION for this column.
  2569.      *      unique
  2570.      *          unique constraint
  2571.      *
  2572.      * @return string
  2573.      */
  2574.     public function getColumnDeclarationListSQL(array $columns)
  2575.     {
  2576.         $declarations = [];
  2577.         foreach ($columns as $name => $column) {
  2578.             $declarations[] = $this->getColumnDeclarationSQL($name$column);
  2579.         }
  2580.         return implode(', '$declarations);
  2581.     }
  2582.     /**
  2583.      * Obtains DBMS specific SQL code portion needed to declare a generic type
  2584.      * column to be used in statements like CREATE TABLE.
  2585.      *
  2586.      * @param string  $name   The name the column to be declared.
  2587.      * @param mixed[] $column An associative array with the name of the properties
  2588.      *                        of the column being declared as array indexes. Currently, the types
  2589.      *                        of supported column properties are as follows:
  2590.      *
  2591.      *      length
  2592.      *          Integer value that determines the maximum length of the text
  2593.      *          column. If this argument is missing the column should be
  2594.      *          declared to have the longest length allowed by the DBMS.
  2595.      *
  2596.      *      default
  2597.      *          Text value to be used as default for this column.
  2598.      *
  2599.      *      notnull
  2600.      *          Boolean flag that indicates whether this column is constrained
  2601.      *          to not be set to null.
  2602.      *      charset
  2603.      *          Text value with the default CHARACTER SET for this column.
  2604.      *      collation
  2605.      *          Text value with the default COLLATION for this column.
  2606.      *      unique
  2607.      *          unique constraint
  2608.      *      check
  2609.      *          column check constraint
  2610.      *      columnDefinition
  2611.      *          a string that defines the complete column
  2612.      *
  2613.      * @return string DBMS specific SQL code portion that should be used to declare the column.
  2614.      *
  2615.      * @throws Exception
  2616.      */
  2617.     public function getColumnDeclarationSQL($name, array $column)
  2618.     {
  2619.         if (isset($column['columnDefinition'])) {
  2620.             $declaration $this->getCustomTypeDeclarationSQL($column);
  2621.         } else {
  2622.             $default $this->getDefaultValueDeclarationSQL($column);
  2623.             $charset = ! empty($column['charset']) ?
  2624.                 ' ' $this->getColumnCharsetDeclarationSQL($column['charset']) : '';
  2625.             $collation = ! empty($column['collation']) ?
  2626.                 ' ' $this->getColumnCollationDeclarationSQL($column['collation']) : '';
  2627.             $notnull = ! empty($column['notnull']) ? ' NOT NULL' '';
  2628.             if (! empty($column['unique'])) {
  2629.                 Deprecation::trigger(
  2630.                     'doctrine/dbal',
  2631.                     'https://github.com/doctrine/dbal/pull/5656',
  2632.                     'The usage of the "unique" column property is deprecated. Use unique constraints instead.',
  2633.                 );
  2634.                 $unique ' ' $this->getUniqueFieldDeclarationSQL();
  2635.             } else {
  2636.                 $unique '';
  2637.             }
  2638.             if (! empty($column['check'])) {
  2639.                 Deprecation::trigger(
  2640.                     'doctrine/dbal',
  2641.                     'https://github.com/doctrine/dbal/pull/5656',
  2642.                     'The usage of the "check" column property is deprecated.',
  2643.                 );
  2644.                 $check ' ' $column['check'];
  2645.             } else {
  2646.                 $check '';
  2647.             }
  2648.             $typeDecl    $column['type']->getSQLDeclaration($column$this);
  2649.             $declaration $typeDecl $charset $default $notnull $unique $check $collation;
  2650.             if ($this->supportsInlineColumnComments() && isset($column['comment']) && $column['comment'] !== '') {
  2651.                 $declaration .= ' ' $this->getInlineColumnCommentSQL($column['comment']);
  2652.             }
  2653.         }
  2654.         return $name ' ' $declaration;
  2655.     }
  2656.     /**
  2657.      * Returns the SQL snippet that declares a floating point column of arbitrary precision.
  2658.      *
  2659.      * @param mixed[] $column
  2660.      *
  2661.      * @return string
  2662.      */
  2663.     public function getDecimalTypeDeclarationSQL(array $column)
  2664.     {
  2665.         if (empty($column['precision'])) {
  2666.             if (! isset($column['precision'])) {
  2667.                 Deprecation::trigger(
  2668.                     'doctrine/dbal',
  2669.                     'https://github.com/doctrine/dbal/pull/5637',
  2670.                     'Relying on the default decimal column precision is deprecated'
  2671.                         ', specify the precision explicitly.',
  2672.                 );
  2673.             }
  2674.             $precision 10;
  2675.         } else {
  2676.             $precision $column['precision'];
  2677.         }
  2678.         if (empty($column['scale'])) {
  2679.             if (! isset($column['scale'])) {
  2680.                 Deprecation::trigger(
  2681.                     'doctrine/dbal',
  2682.                     'https://github.com/doctrine/dbal/pull/5637',
  2683.                     'Relying on the default decimal column scale is deprecated'
  2684.                         ', specify the scale explicitly.',
  2685.                 );
  2686.             }
  2687.             $scale 0;
  2688.         } else {
  2689.             $scale $column['scale'];
  2690.         }
  2691.         return 'NUMERIC(' $precision ', ' $scale ')';
  2692.     }
  2693.     /**
  2694.      * Obtains DBMS specific SQL code portion needed to set a default value
  2695.      * declaration to be used in statements like CREATE TABLE.
  2696.      *
  2697.      * @param mixed[] $column The column definition array.
  2698.      *
  2699.      * @return string DBMS specific SQL code portion needed to set a default value.
  2700.      */
  2701.     public function getDefaultValueDeclarationSQL($column)
  2702.     {
  2703.         if (! isset($column['default'])) {
  2704.             return empty($column['notnull']) ? ' DEFAULT NULL' '';
  2705.         }
  2706.         $default $column['default'];
  2707.         if (! isset($column['type'])) {
  2708.             return " DEFAULT '" $default "'";
  2709.         }
  2710.         $type $column['type'];
  2711.         if ($type instanceof Types\PhpIntegerMappingType) {
  2712.             return ' DEFAULT ' $default;
  2713.         }
  2714.         if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
  2715.             return ' DEFAULT ' $this->getCurrentTimestampSQL();
  2716.         }
  2717.         if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
  2718.             return ' DEFAULT ' $this->getCurrentTimeSQL();
  2719.         }
  2720.         if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
  2721.             return ' DEFAULT ' $this->getCurrentDateSQL();
  2722.         }
  2723.         if ($type instanceof Types\BooleanType) {
  2724.             return ' DEFAULT ' $this->convertBooleans($default);
  2725.         }
  2726.         return ' DEFAULT ' $this->quoteStringLiteral($default);
  2727.     }
  2728.     /**
  2729.      * Obtains DBMS specific SQL code portion needed to set a CHECK constraint
  2730.      * declaration to be used in statements like CREATE TABLE.
  2731.      *
  2732.      * @param string[]|mixed[][] $definition The check definition.
  2733.      *
  2734.      * @return string DBMS specific SQL code portion needed to set a CHECK constraint.
  2735.      */
  2736.     public function getCheckDeclarationSQL(array $definition)
  2737.     {
  2738.         $constraints = [];
  2739.         foreach ($definition as $column => $def) {
  2740.             if (is_string($def)) {
  2741.                 $constraints[] = 'CHECK (' $def ')';
  2742.             } else {
  2743.                 if (isset($def['min'])) {
  2744.                     $constraints[] = 'CHECK (' $column ' >= ' $def['min'] . ')';
  2745.                 }
  2746.                 if (isset($def['max'])) {
  2747.                     $constraints[] = 'CHECK (' $column ' <= ' $def['max'] . ')';
  2748.                 }
  2749.             }
  2750.         }
  2751.         return implode(', '$constraints);
  2752.     }
  2753.     /**
  2754.      * Obtains DBMS specific SQL code portion needed to set a unique
  2755.      * constraint declaration to be used in statements like CREATE TABLE.
  2756.      *
  2757.      * @param string           $name       The name of the unique constraint.
  2758.      * @param UniqueConstraint $constraint The unique constraint definition.
  2759.      *
  2760.      * @return string DBMS specific SQL code portion needed to set a constraint.
  2761.      *
  2762.      * @throws InvalidArgumentException
  2763.      */
  2764.     public function getUniqueConstraintDeclarationSQL($nameUniqueConstraint $constraint)
  2765.     {
  2766.         $columns $constraint->getQuotedColumns($this);
  2767.         $name    = new Identifier($name);
  2768.         if (count($columns) === 0) {
  2769.             throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
  2770.         }
  2771.         $constraintFlags array_merge(['UNIQUE'], array_map('strtoupper'$constraint->getFlags()));
  2772.         $constraintName  $name->getQuotedName($this);
  2773.         $columnListNames $this->getColumnsFieldDeclarationListSQL($columns);
  2774.         return sprintf('CONSTRAINT %s %s (%s)'$constraintNameimplode(' '$constraintFlags), $columnListNames);
  2775.     }
  2776.     /**
  2777.      * Obtains DBMS specific SQL code portion needed to set an index
  2778.      * declaration to be used in statements like CREATE TABLE.
  2779.      *
  2780.      * @param string $name  The name of the index.
  2781.      * @param Index  $index The index definition.
  2782.      *
  2783.      * @return string DBMS specific SQL code portion needed to set an index.
  2784.      *
  2785.      * @throws InvalidArgumentException
  2786.      */
  2787.     public function getIndexDeclarationSQL($nameIndex $index)
  2788.     {
  2789.         $columns $index->getColumns();
  2790.         $name    = new Identifier($name);
  2791.         if (count($columns) === 0) {
  2792.             throw new InvalidArgumentException("Incomplete definition. 'columns' required.");
  2793.         }
  2794.         return $this->getCreateIndexSQLFlags($index) . 'INDEX ' $name->getQuotedName($this)
  2795.             . ' (' $this->getIndexFieldDeclarationListSQL($index) . ')' $this->getPartialIndexSQL($index);
  2796.     }
  2797.     /**
  2798.      * Obtains SQL code portion needed to create a custom column,
  2799.      * e.g. when a column has the "columnDefinition" keyword.
  2800.      * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
  2801.      *
  2802.      * @deprecated
  2803.      *
  2804.      * @param mixed[] $column
  2805.      *
  2806.      * @return string
  2807.      */
  2808.     public function getCustomTypeDeclarationSQL(array $column)
  2809.     {
  2810.         Deprecation::triggerIfCalledFromOutside(
  2811.             'doctrine/dbal',
  2812.             'https://github.com/doctrine/dbal/pull/5527',
  2813.             '%s is deprecated.',
  2814.             __METHOD__,
  2815.         );
  2816.         return $column['columnDefinition'];
  2817.     }
  2818.     /**
  2819.      * Obtains DBMS specific SQL code portion needed to set an index
  2820.      * declaration to be used in statements like CREATE TABLE.
  2821.      *
  2822.      * @deprecated
  2823.      */
  2824.     public function getIndexFieldDeclarationListSQL(Index $index): string
  2825.     {
  2826.         Deprecation::triggerIfCalledFromOutside(
  2827.             'doctrine/dbal',
  2828.             'https://github.com/doctrine/dbal/pull/5527',
  2829.             '%s is deprecated.',
  2830.             __METHOD__,
  2831.         );
  2832.         return implode(', '$index->getQuotedColumns($this));
  2833.     }
  2834.     /**
  2835.      * Obtains DBMS specific SQL code portion needed to set an index
  2836.      * declaration to be used in statements like CREATE TABLE.
  2837.      *
  2838.      * @deprecated
  2839.      *
  2840.      * @param mixed[] $columns
  2841.      */
  2842.     public function getColumnsFieldDeclarationListSQL(array $columns): string
  2843.     {
  2844.         Deprecation::triggerIfCalledFromOutside(
  2845.             'doctrine/dbal',
  2846.             'https://github.com/doctrine/dbal/pull/5527',
  2847.             '%s is deprecated.',
  2848.             __METHOD__,
  2849.         );
  2850.         $ret = [];
  2851.         foreach ($columns as $column => $definition) {
  2852.             if (is_array($definition)) {
  2853.                 $ret[] = $column;
  2854.             } else {
  2855.                 $ret[] = $definition;
  2856.             }
  2857.         }
  2858.         return implode(', '$ret);
  2859.     }
  2860.     /**
  2861.      * Returns the required SQL string that fits between CREATE ... TABLE
  2862.      * to create the table as a temporary table.
  2863.      *
  2864.      * Should be overridden in driver classes to return the correct string for the
  2865.      * specific database type.
  2866.      *
  2867.      * The default is to return the string "TEMPORARY" - this will result in a
  2868.      * SQL error for any database that does not support temporary tables, or that
  2869.      * requires a different SQL command from "CREATE TEMPORARY TABLE".
  2870.      *
  2871.      * @deprecated
  2872.      *
  2873.      * @return string The string required to be placed between "CREATE" and "TABLE"
  2874.      *                to generate a temporary table, if possible.
  2875.      */
  2876.     public function getTemporaryTableSQL()
  2877.     {
  2878.         Deprecation::trigger(
  2879.             'doctrine/dbal',
  2880.             'https://github.com/doctrine/dbal/pull/4724',
  2881.             'AbstractPlatform::getTemporaryTableSQL() is deprecated.',
  2882.         );
  2883.         return 'TEMPORARY';
  2884.     }
  2885.     /**
  2886.      * Some vendors require temporary table names to be qualified specially.
  2887.      *
  2888.      * @param string $tableName
  2889.      *
  2890.      * @return string
  2891.      */
  2892.     public function getTemporaryTableName($tableName)
  2893.     {
  2894.         return $tableName;
  2895.     }
  2896.     /**
  2897.      * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
  2898.      * of a column declaration to be used in statements like CREATE TABLE.
  2899.      *
  2900.      * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
  2901.      *                of a column declaration.
  2902.      */
  2903.     public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
  2904.     {
  2905.         $sql  $this->getForeignKeyBaseDeclarationSQL($foreignKey);
  2906.         $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
  2907.         return $sql;
  2908.     }
  2909.     /**
  2910.      * Returns the FOREIGN KEY query section dealing with non-standard options
  2911.      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
  2912.      *
  2913.      * @param ForeignKeyConstraint $foreignKey The foreign key definition.
  2914.      *
  2915.      * @return string
  2916.      */
  2917.     public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
  2918.     {
  2919.         $query '';
  2920.         if ($foreignKey->hasOption('onUpdate')) {
  2921.             $query .= ' ON UPDATE ' $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
  2922.         }
  2923.         if ($foreignKey->hasOption('onDelete')) {
  2924.             $query .= ' ON DELETE ' $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
  2925.         }
  2926.         return $query;
  2927.     }
  2928.     /**
  2929.      * Returns the given referential action in uppercase if valid, otherwise throws an exception.
  2930.      *
  2931.      * @param string $action The foreign key referential action.
  2932.      *
  2933.      * @return string
  2934.      *
  2935.      * @throws InvalidArgumentException If unknown referential action given.
  2936.      */
  2937.     public function getForeignKeyReferentialActionSQL($action)
  2938.     {
  2939.         $upper strtoupper($action);
  2940.         switch ($upper) {
  2941.             case 'CASCADE':
  2942.             case 'SET NULL':
  2943.             case 'NO ACTION':
  2944.             case 'RESTRICT':
  2945.             case 'SET DEFAULT':
  2946.                 return $upper;
  2947.             default:
  2948.                 throw new InvalidArgumentException('Invalid foreign key action: ' $upper);
  2949.         }
  2950.     }
  2951.     /**
  2952.      * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
  2953.      * of a column declaration to be used in statements like CREATE TABLE.
  2954.      *
  2955.      * @return string
  2956.      *
  2957.      * @throws InvalidArgumentException
  2958.      */
  2959.     public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
  2960.     {
  2961.         $sql '';
  2962.         if (strlen($foreignKey->getName()) > 0) {
  2963.             $sql .= 'CONSTRAINT ' $foreignKey->getQuotedName($this) . ' ';
  2964.         }
  2965.         $sql .= 'FOREIGN KEY (';
  2966.         if (count($foreignKey->getLocalColumns()) === 0) {
  2967.             throw new InvalidArgumentException("Incomplete definition. 'local' required.");
  2968.         }
  2969.         if (count($foreignKey->getForeignColumns()) === 0) {
  2970.             throw new InvalidArgumentException("Incomplete definition. 'foreign' required.");
  2971.         }
  2972.         if (strlen($foreignKey->getForeignTableName()) === 0) {
  2973.             throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
  2974.         }
  2975.         return $sql implode(', '$foreignKey->getQuotedLocalColumns($this))
  2976.             . ') REFERENCES '
  2977.             $foreignKey->getQuotedForeignTableName($this) . ' ('
  2978.             implode(', '$foreignKey->getQuotedForeignColumns($this)) . ')';
  2979.     }
  2980.     /**
  2981.      * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint
  2982.      * of a column declaration to be used in statements like CREATE TABLE.
  2983.      *
  2984.      * @deprecated Use UNIQUE in SQL instead.
  2985.      *
  2986.      * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
  2987.      *                of a column declaration.
  2988.      */
  2989.     public function getUniqueFieldDeclarationSQL()
  2990.     {
  2991.         Deprecation::trigger(
  2992.             'doctrine/dbal',
  2993.             'https://github.com/doctrine/dbal/pull/4724',
  2994.             'AbstractPlatform::getUniqueFieldDeclarationSQL() is deprecated. Use UNIQUE in SQL instead.',
  2995.         );
  2996.         return 'UNIQUE';
  2997.     }
  2998.     /**
  2999.      * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET
  3000.      * of a column declaration to be used in statements like CREATE TABLE.
  3001.      *
  3002.      * @param string $charset The name of the charset.
  3003.      *
  3004.      * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
  3005.      *                of a column declaration.
  3006.      */
  3007.     public function getColumnCharsetDeclarationSQL($charset)
  3008.     {
  3009.         return '';
  3010.     }
  3011.     /**
  3012.      * Obtains DBMS specific SQL code portion needed to set the COLLATION
  3013.      * of a column declaration to be used in statements like CREATE TABLE.
  3014.      *
  3015.      * @param string $collation The name of the collation.
  3016.      *
  3017.      * @return string DBMS specific SQL code portion needed to set the COLLATION
  3018.      *                of a column declaration.
  3019.      */
  3020.     public function getColumnCollationDeclarationSQL($collation)
  3021.     {
  3022.         return $this->supportsColumnCollation() ? 'COLLATE ' $this->quoteSingleIdentifier($collation) : '';
  3023.     }
  3024.     /**
  3025.      * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
  3026.      * Subclasses should override this method to return TRUE if they prefer identity columns.
  3027.      *
  3028.      * @deprecated
  3029.      *
  3030.      * @return bool
  3031.      */
  3032.     public function prefersIdentityColumns()
  3033.     {
  3034.         Deprecation::trigger(
  3035.             'doctrine/dbal',
  3036.             'https://github.com/doctrine/dbal/pull/1519',
  3037.             'AbstractPlatform::prefersIdentityColumns() is deprecated.',
  3038.         );
  3039.         return false;
  3040.     }
  3041.     /**
  3042.      * Some platforms need the boolean values to be converted.
  3043.      *
  3044.      * The default conversion in this implementation converts to integers (false => 0, true => 1).
  3045.      *
  3046.      * Note: if the input is not a boolean the original input might be returned.
  3047.      *
  3048.      * There are two contexts when converting booleans: Literals and Prepared Statements.
  3049.      * This method should handle the literal case
  3050.      *
  3051.      * @param mixed $item A boolean or an array of them.
  3052.      *
  3053.      * @return mixed A boolean database value or an array of them.
  3054.      */
  3055.     public function convertBooleans($item)
  3056.     {
  3057.         if (is_array($item)) {
  3058.             foreach ($item as $k => $value) {
  3059.                 if (! is_bool($value)) {
  3060.                     continue;
  3061.                 }
  3062.                 $item[$k] = (int) $value;
  3063.             }
  3064.         } elseif (is_bool($item)) {
  3065.             $item = (int) $item;
  3066.         }
  3067.         return $item;
  3068.     }
  3069.     /**
  3070.      * Some platforms have boolean literals that needs to be correctly converted
  3071.      *
  3072.      * The default conversion tries to convert value into bool "(bool)$item"
  3073.      *
  3074.      * @param T $item
  3075.      *
  3076.      * @return (T is null ? null : bool)
  3077.      *
  3078.      * @template T
  3079.      */
  3080.     public function convertFromBoolean($item)
  3081.     {
  3082.         return $item === null null : (bool) $item;
  3083.     }
  3084.     /**
  3085.      * This method should handle the prepared statements case. When there is no
  3086.      * distinction, it's OK to use the same method.
  3087.      *
  3088.      * Note: if the input is not a boolean the original input might be returned.
  3089.      *
  3090.      * @param mixed $item A boolean or an array of them.
  3091.      *
  3092.      * @return mixed A boolean database value or an array of them.
  3093.      */
  3094.     public function convertBooleansToDatabaseValue($item)
  3095.     {
  3096.         return $this->convertBooleans($item);
  3097.     }
  3098.     /**
  3099.      * Returns the SQL specific for the platform to get the current date.
  3100.      *
  3101.      * @return string
  3102.      */
  3103.     public function getCurrentDateSQL()
  3104.     {
  3105.         return 'CURRENT_DATE';
  3106.     }
  3107.     /**
  3108.      * Returns the SQL specific for the platform to get the current time.
  3109.      *
  3110.      * @return string
  3111.      */
  3112.     public function getCurrentTimeSQL()
  3113.     {
  3114.         return 'CURRENT_TIME';
  3115.     }
  3116.     /**
  3117.      * Returns the SQL specific for the platform to get the current timestamp
  3118.      *
  3119.      * @return string
  3120.      */
  3121.     public function getCurrentTimestampSQL()
  3122.     {
  3123.         return 'CURRENT_TIMESTAMP';
  3124.     }
  3125.     /**
  3126.      * Returns the SQL for a given transaction isolation level Connection constant.
  3127.      *
  3128.      * @param int $level
  3129.      *
  3130.      * @return string
  3131.      *
  3132.      * @throws InvalidArgumentException
  3133.      */
  3134.     protected function _getTransactionIsolationLevelSQL($level)
  3135.     {
  3136.         switch ($level) {
  3137.             case TransactionIsolationLevel::READ_UNCOMMITTED:
  3138.                 return 'READ UNCOMMITTED';
  3139.             case TransactionIsolationLevel::READ_COMMITTED:
  3140.                 return 'READ COMMITTED';
  3141.             case TransactionIsolationLevel::REPEATABLE_READ:
  3142.                 return 'REPEATABLE READ';
  3143.             case TransactionIsolationLevel::SERIALIZABLE:
  3144.                 return 'SERIALIZABLE';
  3145.             default:
  3146.                 throw new InvalidArgumentException('Invalid isolation level:' $level);
  3147.         }
  3148.     }
  3149.     /**
  3150.      * @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy.
  3151.      *
  3152.      * @return string
  3153.      *
  3154.      * @throws Exception If not supported on this platform.
  3155.      */
  3156.     public function getListDatabasesSQL()
  3157.     {
  3158.         throw Exception::notSupported(__METHOD__);
  3159.     }
  3160.     /**
  3161.      * Returns the SQL statement for retrieving the namespaces defined in the database.
  3162.      *
  3163.      * @deprecated Use {@see AbstractSchemaManager::listSchemaNames()} instead.
  3164.      *
  3165.      * @return string
  3166.      *
  3167.      * @throws Exception If not supported on this platform.
  3168.      */
  3169.     public function getListNamespacesSQL()
  3170.     {
  3171.         Deprecation::triggerIfCalledFromOutside(
  3172.             'doctrine/dbal',
  3173.             'https://github.com/doctrine/dbal/issues/4503',
  3174.             'AbstractPlatform::getListNamespacesSQL() is deprecated,'
  3175.                 ' use AbstractSchemaManager::listSchemaNames() instead.',
  3176.         );
  3177.         throw Exception::notSupported(__METHOD__);
  3178.     }
  3179.     /**
  3180.      * @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy.
  3181.      *
  3182.      * @param string $database
  3183.      *
  3184.      * @return string
  3185.      *
  3186.      * @throws Exception If not supported on this platform.
  3187.      */
  3188.     public function getListSequencesSQL($database)
  3189.     {
  3190.         throw Exception::notSupported(__METHOD__);
  3191.     }
  3192.     /**
  3193.      * @deprecated
  3194.      *
  3195.      * @param string $table
  3196.      *
  3197.      * @return string
  3198.      *
  3199.      * @throws Exception If not supported on this platform.
  3200.      */
  3201.     public function getListTableConstraintsSQL($table)
  3202.     {
  3203.         throw Exception::notSupported(__METHOD__);
  3204.     }
  3205.     /**
  3206.      * @deprecated The SQL used for schema introspection is an implementation detail and should not be relied upon.
  3207.      *
  3208.      * @param string $table
  3209.      * @param string $database
  3210.      *
  3211.      * @return string
  3212.      *
  3213.      * @throws Exception If not supported on this platform.
  3214.      */
  3215.     public function getListTableColumnsSQL($table$database null)
  3216.     {
  3217.         throw Exception::notSupported(__METHOD__);
  3218.     }
  3219.     /**
  3220.      * @deprecated The SQL used for schema introspection is an implementation detail and should not be relied upon.
  3221.      *
  3222.      * @return string
  3223.      *
  3224.      * @throws Exception If not supported on this platform.
  3225.      */
  3226.     public function getListTablesSQL()
  3227.     {
  3228.         throw Exception::notSupported(__METHOD__);
  3229.     }
  3230.     /**
  3231.      * @deprecated
  3232.      *
  3233.      * @return string
  3234.      *
  3235.      * @throws Exception If not supported on this platform.
  3236.      */
  3237.     public function getListUsersSQL()
  3238.     {
  3239.         Deprecation::trigger(
  3240.             'doctrine/dbal',
  3241.             'https://github.com/doctrine/dbal/pull/4724',
  3242.             'AbstractPlatform::getListUsersSQL() is deprecated.',
  3243.         );
  3244.         throw Exception::notSupported(__METHOD__);
  3245.     }
  3246.     /**
  3247.      * Returns the SQL to list all views of a database or user.
  3248.      *
  3249.      * @internal The method should be only used from within the {@see AbstractSchemaManager} class hierarchy.
  3250.      *
  3251.      * @param string $database
  3252.      *
  3253.      * @return string
  3254.      *
  3255.      * @throws Exception If not supported on this platform.
  3256.      */
  3257.     public function getListViewsSQL($database)
  3258.     {
  3259.         throw Exception::notSupported(__METHOD__);
  3260.     }
  3261.     /**
  3262.      * @deprecated The SQL used for schema introspection is an implementation detail and should not be relied upon.
  3263.      *
  3264.      * Returns the list of indexes for the current database.
  3265.      *
  3266.      * The current database parameter is optional but will always be passed
  3267.      * when using the SchemaManager API and is the database the given table is in.
  3268.      *
  3269.      * Attention: Some platforms only support currentDatabase when they
  3270.      * are connected with that database. Cross-database information schema
  3271.      * requests may be impossible.
  3272.      *
  3273.      * @param string $table
  3274.      * @param string $database
  3275.      *
  3276.      * @return string
  3277.      *
  3278.      * @throws Exception If not supported on this platform.
  3279.      */
  3280.     public function getListTableIndexesSQL($table$database null)
  3281.     {
  3282.         throw Exception::notSupported(__METHOD__);
  3283.     }
  3284.     /**
  3285.      * @deprecated The SQL used for schema introspection is an implementation detail and should not be relied upon.
  3286.      *
  3287.      * @param string $table
  3288.      *
  3289.      * @return string
  3290.      *
  3291.      * @throws Exception If not supported on this platform.
  3292.      */
  3293.     public function getListTableForeignKeysSQL($table)
  3294.     {
  3295.         throw Exception::notSupported(__METHOD__);
  3296.     }
  3297.     /**
  3298.      * @param string $name
  3299.      * @param string $sql
  3300.      *
  3301.      * @return string
  3302.      */
  3303.     public function getCreateViewSQL($name$sql)
  3304.     {
  3305.         return 'CREATE VIEW ' $name ' AS ' $sql;
  3306.     }
  3307.     /**
  3308.      * @param string $name
  3309.      *
  3310.      * @return string
  3311.      */
  3312.     public function getDropViewSQL($name)
  3313.     {
  3314.         return 'DROP VIEW ' $name;
  3315.     }
  3316.     /**
  3317.      * @param string $sequence
  3318.      *
  3319.      * @return string
  3320.      *
  3321.      * @throws Exception If not supported on this platform.
  3322.      */
  3323.     public function getSequenceNextValSQL($sequence)
  3324.     {
  3325.         throw Exception::notSupported(__METHOD__);
  3326.     }
  3327.     /**
  3328.      * Returns the SQL to create a new database.
  3329.      *
  3330.      * @param string $name The name of the database that should be created.
  3331.      *
  3332.      * @return string
  3333.      *
  3334.      * @throws Exception If not supported on this platform.
  3335.      */
  3336.     public function getCreateDatabaseSQL($name)
  3337.     {
  3338.         if (! $this->supportsCreateDropDatabase()) {
  3339.             throw Exception::notSupported(__METHOD__);
  3340.         }
  3341.         return 'CREATE DATABASE ' $name;
  3342.     }
  3343.     /**
  3344.      * Returns the SQL snippet to drop an existing database.
  3345.      *
  3346.      * @param string $name The name of the database that should be dropped.
  3347.      *
  3348.      * @return string
  3349.      */
  3350.     public function getDropDatabaseSQL($name)
  3351.     {
  3352.         if (! $this->supportsCreateDropDatabase()) {
  3353.             throw Exception::notSupported(__METHOD__);
  3354.         }
  3355.         return 'DROP DATABASE ' $name;
  3356.     }
  3357.     /**
  3358.      * Returns the SQL to set the transaction isolation level.
  3359.      *
  3360.      * @param int $level
  3361.      *
  3362.      * @return string
  3363.      *
  3364.      * @throws Exception If not supported on this platform.
  3365.      */
  3366.     public function getSetTransactionIsolationSQL($level)
  3367.     {
  3368.         throw Exception::notSupported(__METHOD__);
  3369.     }
  3370.     /**
  3371.      * Obtains DBMS specific SQL to be used to create datetime columns in
  3372.      * statements like CREATE TABLE.
  3373.      *
  3374.      * @param mixed[] $column
  3375.      *
  3376.      * @return string
  3377.      *
  3378.      * @throws Exception If not supported on this platform.
  3379.      */
  3380.     public function getDateTimeTypeDeclarationSQL(array $column)
  3381.     {
  3382.         throw Exception::notSupported(__METHOD__);
  3383.     }
  3384.     /**
  3385.      * Obtains DBMS specific SQL to be used to create datetime with timezone offset columns.
  3386.      *
  3387.      * @param mixed[] $column
  3388.      *
  3389.      * @return string
  3390.      */
  3391.     public function getDateTimeTzTypeDeclarationSQL(array $column)
  3392.     {
  3393.         return $this->getDateTimeTypeDeclarationSQL($column);
  3394.     }
  3395.     /**
  3396.      * Obtains DBMS specific SQL to be used to create date columns in statements
  3397.      * like CREATE TABLE.
  3398.      *
  3399.      * @param mixed[] $column
  3400.      *
  3401.      * @return string
  3402.      *
  3403.      * @throws Exception If not supported on this platform.
  3404.      */
  3405.     public function getDateTypeDeclarationSQL(array $column)
  3406.     {
  3407.         throw Exception::notSupported(__METHOD__);
  3408.     }
  3409.     /**
  3410.      * Obtains DBMS specific SQL to be used to create time columns in statements
  3411.      * like CREATE TABLE.
  3412.      *
  3413.      * @param mixed[] $column
  3414.      *
  3415.      * @return string
  3416.      *
  3417.      * @throws Exception If not supported on this platform.
  3418.      */
  3419.     public function getTimeTypeDeclarationSQL(array $column)
  3420.     {
  3421.         throw Exception::notSupported(__METHOD__);
  3422.     }
  3423.     /**
  3424.      * @param mixed[] $column
  3425.      *
  3426.      * @return string
  3427.      */
  3428.     public function getFloatDeclarationSQL(array $column)
  3429.     {
  3430.         return 'DOUBLE PRECISION';
  3431.     }
  3432.     /**
  3433.      * Gets the default transaction isolation level of the platform.
  3434.      *
  3435.      * @see TransactionIsolationLevel
  3436.      *
  3437.      * @return TransactionIsolationLevel::* The default isolation level.
  3438.      */
  3439.     public function getDefaultTransactionIsolationLevel()
  3440.     {
  3441.         return TransactionIsolationLevel::READ_COMMITTED;
  3442.     }
  3443.     /* supports*() methods */
  3444.     /**
  3445.      * Whether the platform supports sequences.
  3446.      *
  3447.      * @return bool
  3448.      */
  3449.     public function supportsSequences()
  3450.     {
  3451.         return false;
  3452.     }
  3453.     /**
  3454.      * Whether the platform supports identity columns.
  3455.      *
  3456.      * Identity columns are columns that receive an auto-generated value from the
  3457.      * database on insert of a row.
  3458.      *
  3459.      * @return bool
  3460.      */
  3461.     public function supportsIdentityColumns()
  3462.     {
  3463.         return false;
  3464.     }
  3465.     /**
  3466.      * Whether the platform emulates identity columns through sequences.
  3467.      *
  3468.      * Some platforms that do not support identity columns natively
  3469.      * but support sequences can emulate identity columns by using
  3470.      * sequences.
  3471.      *
  3472.      * @deprecated
  3473.      *
  3474.      * @return bool
  3475.      */
  3476.     public function usesSequenceEmulatedIdentityColumns()
  3477.     {
  3478.         Deprecation::trigger(
  3479.             'doctrine/dbal',
  3480.             'https://github.com/doctrine/dbal/pull/5513',
  3481.             '%s is deprecated.',
  3482.             __METHOD__,
  3483.         );
  3484.         return false;
  3485.     }
  3486.     /**
  3487.      * Returns the name of the sequence for a particular identity column in a particular table.
  3488.      *
  3489.      * @deprecated
  3490.      *
  3491.      * @see usesSequenceEmulatedIdentityColumns
  3492.      *
  3493.      * @param string $tableName  The name of the table to return the sequence name for.
  3494.      * @param string $columnName The name of the identity column in the table to return the sequence name for.
  3495.      *
  3496.      * @return string
  3497.      *
  3498.      * @throws Exception If not supported on this platform.
  3499.      */
  3500.     public function getIdentitySequenceName($tableName$columnName)
  3501.     {
  3502.         throw Exception::notSupported(__METHOD__);
  3503.     }
  3504.     /**
  3505.      * Whether the platform supports indexes.
  3506.      *
  3507.      * @deprecated
  3508.      *
  3509.      * @return bool
  3510.      */
  3511.     public function supportsIndexes()
  3512.     {
  3513.         Deprecation::trigger(
  3514.             'doctrine/dbal',
  3515.             'https://github.com/doctrine/dbal/pull/4724',
  3516.             'AbstractPlatform::supportsIndexes() is deprecated.',
  3517.         );
  3518.         return true;
  3519.     }
  3520.     /**
  3521.      * Whether the platform supports partial indexes.
  3522.      *
  3523.      * @return bool
  3524.      */
  3525.     public function supportsPartialIndexes()
  3526.     {
  3527.         return false;
  3528.     }
  3529.     /**
  3530.      * Whether the platform supports indexes with column length definitions.
  3531.      */
  3532.     public function supportsColumnLengthIndexes(): bool
  3533.     {
  3534.         return false;
  3535.     }
  3536.     /**
  3537.      * Whether the platform supports altering tables.
  3538.      *
  3539.      * @deprecated All platforms must implement altering tables.
  3540.      *
  3541.      * @return bool
  3542.      */
  3543.     public function supportsAlterTable()
  3544.     {
  3545.         Deprecation::trigger(
  3546.             'doctrine/dbal',
  3547.             'https://github.com/doctrine/dbal/pull/4724',
  3548.             'AbstractPlatform::supportsAlterTable() is deprecated. All platforms must implement altering tables.',
  3549.         );
  3550.         return true;
  3551.     }
  3552.     /**
  3553.      * Whether the platform supports transactions.
  3554.      *
  3555.      * @deprecated
  3556.      *
  3557.      * @return bool
  3558.      */
  3559.     public function supportsTransactions()
  3560.     {
  3561.         Deprecation::trigger(
  3562.             'doctrine/dbal',
  3563.             'https://github.com/doctrine/dbal/pull/4724',
  3564.             'AbstractPlatform::supportsTransactions() is deprecated.',
  3565.         );
  3566.         return true;
  3567.     }
  3568.     /**
  3569.      * Whether the platform supports savepoints.
  3570.      *
  3571.      * @return bool
  3572.      */
  3573.     public function supportsSavepoints()
  3574.     {
  3575.         return true;
  3576.     }
  3577.     /**
  3578.      * Whether the platform supports releasing savepoints.
  3579.      *
  3580.      * @return bool
  3581.      */
  3582.     public function supportsReleaseSavepoints()
  3583.     {
  3584.         return $this->supportsSavepoints();
  3585.     }
  3586.     /**
  3587.      * Whether the platform supports primary key constraints.
  3588.      *
  3589.      * @deprecated
  3590.      *
  3591.      * @return bool
  3592.      */
  3593.     public function supportsPrimaryConstraints()
  3594.     {
  3595.         Deprecation::trigger(
  3596.             'doctrine/dbal',
  3597.             'https://github.com/doctrine/dbal/pull/4724',
  3598.             'AbstractPlatform::supportsPrimaryConstraints() is deprecated.',
  3599.         );
  3600.         return true;
  3601.     }
  3602.     /**
  3603.      * Whether the platform supports foreign key constraints.
  3604.      *
  3605.      * @deprecated All platforms should support foreign key constraints.
  3606.      *
  3607.      * @return bool
  3608.      */
  3609.     public function supportsForeignKeyConstraints()
  3610.     {
  3611.         Deprecation::triggerIfCalledFromOutside(
  3612.             'doctrine/dbal',
  3613.             'https://github.com/doctrine/dbal/pull/5409',
  3614.             'AbstractPlatform::supportsForeignKeyConstraints() is deprecated.',
  3615.         );
  3616.         return true;
  3617.     }
  3618.     /**
  3619.      * Whether the platform supports database schemas.
  3620.      *
  3621.      * @return bool
  3622.      */
  3623.     public function supportsSchemas()
  3624.     {
  3625.         return false;
  3626.     }
  3627.     /**
  3628.      * Whether this platform can emulate schemas.
  3629.      *
  3630.      * @deprecated
  3631.      *
  3632.      * Platforms that either support or emulate schemas don't automatically
  3633.      * filter a schema for the namespaced elements in {@see AbstractManager::introspectSchema()}.
  3634.      *
  3635.      * @return bool
  3636.      */
  3637.     public function canEmulateSchemas()
  3638.     {
  3639.         Deprecation::trigger(
  3640.             'doctrine/dbal',
  3641.             'https://github.com/doctrine/dbal/pull/4805',
  3642.             'AbstractPlatform::canEmulateSchemas() is deprecated.',
  3643.         );
  3644.         return false;
  3645.     }
  3646.     /**
  3647.      * Returns the default schema name.
  3648.      *
  3649.      * @deprecated
  3650.      *
  3651.      * @return string
  3652.      *
  3653.      * @throws Exception If not supported on this platform.
  3654.      */
  3655.     public function getDefaultSchemaName()
  3656.     {
  3657.         throw Exception::notSupported(__METHOD__);
  3658.     }
  3659.     /**
  3660.      * Whether this platform supports create database.
  3661.      *
  3662.      * Some databases don't allow to create and drop databases at all or only with certain tools.
  3663.      *
  3664.      * @deprecated
  3665.      *
  3666.      * @return bool
  3667.      */
  3668.     public function supportsCreateDropDatabase()
  3669.     {
  3670.         Deprecation::triggerIfCalledFromOutside(
  3671.             'doctrine/dbal',
  3672.             'https://github.com/doctrine/dbal/pull/5513',
  3673.             '%s is deprecated.',
  3674.             __METHOD__,
  3675.         );
  3676.         return true;
  3677.     }
  3678.     /**
  3679.      * Whether the platform supports getting the affected rows of a recent update/delete type query.
  3680.      *
  3681.      * @deprecated
  3682.      *
  3683.      * @return bool
  3684.      */
  3685.     public function supportsGettingAffectedRows()
  3686.     {
  3687.         Deprecation::trigger(
  3688.             'doctrine/dbal',
  3689.             'https://github.com/doctrine/dbal/pull/4724',
  3690.             'AbstractPlatform::supportsGettingAffectedRows() is deprecated.',
  3691.         );
  3692.         return true;
  3693.     }
  3694.     /**
  3695.      * Whether this platform support to add inline column comments as postfix.
  3696.      *
  3697.      * @return bool
  3698.      */
  3699.     public function supportsInlineColumnComments()
  3700.     {
  3701.         return false;
  3702.     }
  3703.     /**
  3704.      * Whether this platform support the proprietary syntax "COMMENT ON asset".
  3705.      *
  3706.      * @return bool
  3707.      */
  3708.     public function supportsCommentOnStatement()
  3709.     {
  3710.         return false;
  3711.     }
  3712.     /**
  3713.      * Does this platform have native guid type.
  3714.      *
  3715.      * @deprecated
  3716.      *
  3717.      * @return bool
  3718.      */
  3719.     public function hasNativeGuidType()
  3720.     {
  3721.         Deprecation::triggerIfCalledFromOutside(
  3722.             'doctrine/dbal',
  3723.             'https://github.com/doctrine/dbal/pull/5509',
  3724.             '%s is deprecated.',
  3725.             __METHOD__,
  3726.         );
  3727.         return false;
  3728.     }
  3729.     /**
  3730.      * Does this platform have native JSON type.
  3731.      *
  3732.      * @deprecated
  3733.      *
  3734.      * @return bool
  3735.      */
  3736.     public function hasNativeJsonType()
  3737.     {
  3738.         Deprecation::triggerIfCalledFromOutside(
  3739.             'doctrine/dbal',
  3740.             'https://github.com/doctrine/dbal/pull/5509',
  3741.             '%s is deprecated.',
  3742.             __METHOD__,
  3743.         );
  3744.         return false;
  3745.     }
  3746.     /**
  3747.      * Whether this platform supports views.
  3748.      *
  3749.      * @deprecated All platforms must implement support for views.
  3750.      *
  3751.      * @return bool
  3752.      */
  3753.     public function supportsViews()
  3754.     {
  3755.         Deprecation::trigger(
  3756.             'doctrine/dbal',
  3757.             'https://github.com/doctrine/dbal/pull/4724',
  3758.             'AbstractPlatform::supportsViews() is deprecated. All platforms must implement support for views.',
  3759.         );
  3760.         return true;
  3761.     }
  3762.     /**
  3763.      * Does this platform support column collation?
  3764.      *
  3765.      * @return bool
  3766.      */
  3767.     public function supportsColumnCollation()
  3768.     {
  3769.         return false;
  3770.     }
  3771.     /**
  3772.      * Gets the format string, as accepted by the date() function, that describes
  3773.      * the format of a stored datetime value of this platform.
  3774.      *
  3775.      * @return string The format string.
  3776.      */
  3777.     public function getDateTimeFormatString()
  3778.     {
  3779.         return 'Y-m-d H:i:s';
  3780.     }
  3781.     /**
  3782.      * Gets the format string, as accepted by the date() function, that describes
  3783.      * the format of a stored datetime with timezone value of this platform.
  3784.      *
  3785.      * @return string The format string.
  3786.      */
  3787.     public function getDateTimeTzFormatString()
  3788.     {
  3789.         return 'Y-m-d H:i:s';
  3790.     }
  3791.     /**
  3792.      * Gets the format string, as accepted by the date() function, that describes
  3793.      * the format of a stored date value of this platform.
  3794.      *
  3795.      * @return string The format string.
  3796.      */
  3797.     public function getDateFormatString()
  3798.     {
  3799.         return 'Y-m-d';
  3800.     }
  3801.     /**
  3802.      * Gets the format string, as accepted by the date() function, that describes
  3803.      * the format of a stored time value of this platform.
  3804.      *
  3805.      * @return string The format string.
  3806.      */
  3807.     public function getTimeFormatString()
  3808.     {
  3809.         return 'H:i:s';
  3810.     }
  3811.     /**
  3812.      * Adds an driver-specific LIMIT clause to the query.
  3813.      *
  3814.      * @param string   $query
  3815.      * @param int|null $limit
  3816.      * @param int      $offset
  3817.      *
  3818.      * @throws Exception
  3819.      */
  3820.     final public function modifyLimitQuery($query$limit$offset 0): string
  3821.     {
  3822.         if ($offset 0) {
  3823.             throw new Exception(sprintf(
  3824.                 'Offset must be a positive integer or zero, %d given',
  3825.                 $offset,
  3826.             ));
  3827.         }
  3828.         if ($offset && ! $this->supportsLimitOffset()) {
  3829.             throw new Exception(sprintf(
  3830.                 'Platform %s does not support offset values in limit queries.',
  3831.                 $this->getName(),
  3832.             ));
  3833.         }
  3834.         if ($limit !== null) {
  3835.             $limit = (int) $limit;
  3836.         }
  3837.         return $this->doModifyLimitQuery($query$limit, (int) $offset);
  3838.     }
  3839.     /**
  3840.      * Adds an platform-specific LIMIT clause to the query.
  3841.      *
  3842.      * @param string   $query
  3843.      * @param int|null $limit
  3844.      * @param int      $offset
  3845.      *
  3846.      * @return string
  3847.      */
  3848.     protected function doModifyLimitQuery($query$limit$offset)
  3849.     {
  3850.         if ($limit !== null) {
  3851.             $query .= sprintf(' LIMIT %d'$limit);
  3852.         }
  3853.         if ($offset 0) {
  3854.             $query .= sprintf(' OFFSET %d'$offset);
  3855.         }
  3856.         return $query;
  3857.     }
  3858.     /**
  3859.      * Whether the database platform support offsets in modify limit clauses.
  3860.      *
  3861.      * @deprecated All platforms must implement support for offsets in modify limit clauses.
  3862.      *
  3863.      * @return bool
  3864.      */
  3865.     public function supportsLimitOffset()
  3866.     {
  3867.         Deprecation::triggerIfCalledFromOutside(
  3868.             'doctrine/dbal',
  3869.             'https://github.com/doctrine/dbal/pull/4724',
  3870.             'AbstractPlatform::supportsViews() is deprecated.'
  3871.             ' All platforms must implement support for offsets in modify limit clauses.',
  3872.         );
  3873.         return true;
  3874.     }
  3875.     /**
  3876.      * Maximum length of any given database identifier, like tables or column names.
  3877.      *
  3878.      * @return int
  3879.      */
  3880.     public function getMaxIdentifierLength()
  3881.     {
  3882.         return 63;
  3883.     }
  3884.     /**
  3885.      * Returns the insert SQL for an empty insert statement.
  3886.      *
  3887.      * @param string $quotedTableName
  3888.      * @param string $quotedIdentifierColumnName
  3889.      *
  3890.      * @return string
  3891.      */
  3892.     public function getEmptyIdentityInsertSQL($quotedTableName$quotedIdentifierColumnName)
  3893.     {
  3894.         return 'INSERT INTO ' $quotedTableName ' (' $quotedIdentifierColumnName ') VALUES (null)';
  3895.     }
  3896.     /**
  3897.      * Generates a Truncate Table SQL statement for a given table.
  3898.      *
  3899.      * Cascade is not supported on many platforms but would optionally cascade the truncate by
  3900.      * following the foreign keys.
  3901.      *
  3902.      * @param string $tableName
  3903.      * @param bool   $cascade
  3904.      *
  3905.      * @return string
  3906.      */
  3907.     public function getTruncateTableSQL($tableName$cascade false)
  3908.     {
  3909.         $tableIdentifier = new Identifier($tableName);
  3910.         return 'TRUNCATE ' $tableIdentifier->getQuotedName($this);
  3911.     }
  3912.     /**
  3913.      * This is for test reasons, many vendors have special requirements for dummy statements.
  3914.      *
  3915.      * @return string
  3916.      */
  3917.     public function getDummySelectSQL()
  3918.     {
  3919.         $expression func_num_args() > func_get_arg(0) : '1';
  3920.         return sprintf('SELECT %s'$expression);
  3921.     }
  3922.     /**
  3923.      * Returns the SQL to create a new savepoint.
  3924.      *
  3925.      * @param string $savepoint
  3926.      *
  3927.      * @return string
  3928.      */
  3929.     public function createSavePoint($savepoint)
  3930.     {
  3931.         return 'SAVEPOINT ' $savepoint;
  3932.     }
  3933.     /**
  3934.      * Returns the SQL to release a savepoint.
  3935.      *
  3936.      * @param string $savepoint
  3937.      *
  3938.      * @return string
  3939.      */
  3940.     public function releaseSavePoint($savepoint)
  3941.     {
  3942.         return 'RELEASE SAVEPOINT ' $savepoint;
  3943.     }
  3944.     /**
  3945.      * Returns the SQL to rollback a savepoint.
  3946.      *
  3947.      * @param string $savepoint
  3948.      *
  3949.      * @return string
  3950.      */
  3951.     public function rollbackSavePoint($savepoint)
  3952.     {
  3953.         return 'ROLLBACK TO SAVEPOINT ' $savepoint;
  3954.     }
  3955.     /**
  3956.      * Returns the keyword list instance of this platform.
  3957.      *
  3958.      * @throws Exception If no keyword list is specified.
  3959.      */
  3960.     final public function getReservedKeywordsList(): KeywordList
  3961.     {
  3962.         // Store the instance so it doesn't need to be generated on every request.
  3963.         return $this->_keywords ??= $this->createReservedKeywordsList();
  3964.     }
  3965.     /**
  3966.      * Creates an instance of the reserved keyword list of this platform.
  3967.      *
  3968.      * This method will become @abstract in DBAL 4.0.0.
  3969.      *
  3970.      * @throws Exception
  3971.      */
  3972.     protected function createReservedKeywordsList(): KeywordList
  3973.     {
  3974.         $class    $this->getReservedKeywordsClass();
  3975.         $keywords = new $class();
  3976.         if (! $keywords instanceof KeywordList) {
  3977.             throw Exception::notSupported(__METHOD__);
  3978.         }
  3979.         return $keywords;
  3980.     }
  3981.     /**
  3982.      * Returns the class name of the reserved keywords list.
  3983.      *
  3984.      * @deprecated Implement {@see createReservedKeywordsList()} instead.
  3985.      *
  3986.      * @return string
  3987.      * @psalm-return class-string<KeywordList>
  3988.      *
  3989.      * @throws Exception If not supported on this platform.
  3990.      */
  3991.     protected function getReservedKeywordsClass()
  3992.     {
  3993.         Deprecation::triggerIfCalledFromOutside(
  3994.             'doctrine/dbal',
  3995.             'https://github.com/doctrine/dbal/issues/4510',
  3996.             'AbstractPlatform::getReservedKeywordsClass() is deprecated,'
  3997.                 ' use AbstractPlatform::createReservedKeywordsList() instead.',
  3998.         );
  3999.         throw Exception::notSupported(__METHOD__);
  4000.     }
  4001.     /**
  4002.      * Quotes a literal string.
  4003.      * This method is NOT meant to fix SQL injections!
  4004.      * It is only meant to escape this platform's string literal
  4005.      * quote character inside the given literal string.
  4006.      *
  4007.      * @param string $str The literal string to be quoted.
  4008.      *
  4009.      * @return string The quoted literal string.
  4010.      */
  4011.     public function quoteStringLiteral($str)
  4012.     {
  4013.         $c $this->getStringLiteralQuoteCharacter();
  4014.         return $c str_replace($c$c $c$str) . $c;
  4015.     }
  4016.     /**
  4017.      * Gets the character used for string literal quoting.
  4018.      *
  4019.      * @deprecated Use {@see quoteStringLiteral()} to quote string literals instead.
  4020.      *
  4021.      * @return string
  4022.      */
  4023.     public function getStringLiteralQuoteCharacter()
  4024.     {
  4025.         Deprecation::triggerIfCalledFromOutside(
  4026.             'doctrine/dbal',
  4027.             'https://github.com/doctrine/dbal/pull/5388',
  4028.             'AbstractPlatform::getStringLiteralQuoteCharacter() is deprecated.'
  4029.                 ' Use quoteStringLiteral() instead.',
  4030.         );
  4031.         return "'";
  4032.     }
  4033.     /**
  4034.      * Escapes metacharacters in a string intended to be used with a LIKE
  4035.      * operator.
  4036.      *
  4037.      * @param string $inputString a literal, unquoted string
  4038.      * @param string $escapeChar  should be reused by the caller in the LIKE
  4039.      *                            expression.
  4040.      */
  4041.     final public function escapeStringForLike(string $inputStringstring $escapeChar): string
  4042.     {
  4043.         return preg_replace(
  4044.             '~([' preg_quote($this->getLikeWildcardCharacters() . $escapeChar'~') . '])~u',
  4045.             addcslashes($escapeChar'\\') . '$1',
  4046.             $inputString,
  4047.         );
  4048.     }
  4049.     /**
  4050.      * @return array<string,mixed> An associative array with the name of the properties
  4051.      *                             of the column being declared as array indexes.
  4052.      */
  4053.     private function columnToArray(Column $column): array
  4054.     {
  4055.         $name $column->getQuotedName($this);
  4056.         return array_merge($column->toArray(), [
  4057.             'name' => $name,
  4058.             'version' => $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false,
  4059.             'comment' => $this->getColumnComment($column),
  4060.         ]);
  4061.     }
  4062.     /** @internal */
  4063.     public function createSQLParser(): Parser
  4064.     {
  4065.         return new Parser(false);
  4066.     }
  4067.     protected function getLikeWildcardCharacters(): string
  4068.     {
  4069.         return '%_';
  4070.     }
  4071.     /**
  4072.      * Compares the definitions of the given columns in the context of this platform.
  4073.      *
  4074.      * @throws Exception
  4075.      */
  4076.     public function columnsEqual(Column $column1Column $column2): bool
  4077.     {
  4078.         $column1Array $this->columnToArray($column1);
  4079.         $column2Array $this->columnToArray($column2);
  4080.         // ignore explicit columnDefinition since it's not set on the Column generated by the SchemaManager
  4081.         unset($column1Array['columnDefinition']);
  4082.         unset($column2Array['columnDefinition']);
  4083.         if (
  4084.             $this->getColumnDeclarationSQL(''$column1Array)
  4085.             !== $this->getColumnDeclarationSQL(''$column2Array)
  4086.         ) {
  4087.             return false;
  4088.         }
  4089.         if (! $this->columnDeclarationsMatch($column1$column2)) {
  4090.             return false;
  4091.         }
  4092.         // If the platform supports inline comments, all comparison is already done above
  4093.         if ($this->supportsInlineColumnComments()) {
  4094.             return true;
  4095.         }
  4096.         if ($column1->getComment() !== $column2->getComment()) {
  4097.             return false;
  4098.         }
  4099.         return $column1->getType() === $column2->getType();
  4100.     }
  4101.     /**
  4102.      * Whether the database data type matches that expected for the doctrine type for the given colunms.
  4103.      */
  4104.     private function columnDeclarationsMatch(Column $column1Column $column2): bool
  4105.     {
  4106.         return ! (
  4107.             $column1->hasPlatformOption('declarationMismatch') ||
  4108.             $column2->hasPlatformOption('declarationMismatch')
  4109.         );
  4110.     }
  4111.     /**
  4112.      * Creates the schema manager that can be used to inspect and change the underlying
  4113.      * database schema according to the dialect of the platform.
  4114.      *
  4115.      * @throws Exception
  4116.      *
  4117.      * @abstract
  4118.      */
  4119.     public function createSchemaManager(Connection $connection): AbstractSchemaManager
  4120.     {
  4121.         throw Exception::notSupported(__METHOD__);
  4122.     }
  4123. }