diff --git a/.scrutinizer.yml b/.scrutinizer.yml index a3b8a5621ca..031103d47d8 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,7 +21,7 @@ before_commands: tools: external_code_coverage: timeout: 3600 - runs: 30 # 25x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP + runs: 29 # 24x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP filter: excluded_paths: diff --git a/.travis.yml b/.travis.yml index e0d87665991..0e014417efa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -187,13 +187,6 @@ jobs: env: DB=mariadb.mysqli MARIADB_VERSION=10.3 COVERAGE=yes addons: mariadb: 10.3 - - stage: Test - php: 7.3 - env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes - services: - - postgresql - addons: - postgresql: "9.2" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes diff --git a/UPGRADE.md b/UPGRADE.md index ad366845ef7..3ac0f42da79 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,3 +1,303 @@ +# Upgrade to 3.0 + +## BC BREAK: Changes in handling string and binary columns + +- When generating schema DDL, DBAL no longer provides the default length for string and binary columns. The application may need to provide the column length if required by the target platform. +- The `\DBAL\Platforms\AbstractPlatform::getVarcharTypeDeclarationSQL()` method has been renamed to `::getStringTypeDeclarationSQL()`. +- The following `AbstractPlatform` methods have been removed as no longer relevant: `::getCharMaxLength()`, `::getVarcharMaxLength()`, `::getVarcharDefaultLength()`, `::getBinaryMaxLength()`, `::getBinaryDefaultLength()`. + +## BC BREAK: Changes in `Doctrine\DBAL\Event\SchemaCreateTableEventArgs` + +Table columns are no longer indexed by column name. Use the `name` attribute of the column instead. + +## BC BREAK: Changes in the `Doctrine\DBAL\Schema` API + +- Column precision no longer defaults to 10. The default value is NULL. +- Asset names are no longer nullable. An empty asset name should be represented as an empty string. +- `Doctrine\DBAL\Schema\AbstractSchemaManager::_getPortableTriggersList()` and `::_getPortableTriggerDefinition()` have been removed. + +## BC BREAK: Changes in the `Doctrine\DBAL\Event` API + +- `SchemaAlterTableAddColumnEventArgs::addSql()` and the same method in other `SchemaEventArgs`-based classes no longer accept an array of SQL statements. They accept a variadic string. +- `ConnectionEventArgs::getDriver()`, `::getDatabasePlatform()` and `::getSchemaManager()` methods have been removed. The connection information can be obtained from the connection which is available via `::getConnection()`. +- `SchemaColumnDefinitionEventArgs::getDatabasePlatform()` and `SchemaIndexDefinitionEventArgs::getDatabasePlatform()` have been removed for the same reason as above. + +## BC BREAK: Changes in the `Doctrine\DBAL\Connection` API + +- The following methods have been removed as leaking internal implementation details: `::getHost()`, `::getPort()`, `::getUsername()`, `::getPassword()`. +- The `::getDatabase()` method can now return null which means that no database is currently selected. + +## BC BREAK: Changes in `Doctrine\DBAL\Driver\SQLSrv\LastInsertId` + +- The class stores the last inserted ID as a nullable string, not an integer, which is reflected in the method signatures. + +## BC BREAK: Changes in the `Doctrine\DBAL\Schema` API + +- Method `Doctrine\DBAL\Schema\AbstractSchemaManager::_getPortableViewDefinition()` no longer optionally returns false. It will always return a `Doctrine\DBAL\Schema\View` instance. +- Method `Doctrine\DBAL\Schema\Comparator::diffTable()` now optionally returns null instead of false. +- Property `Doctrine\DBAL\Schema\TableDiff::$newName` is now optionally null instead of false. +- Method `Doctrine\DBAL\Schema\AbstractSchemaManager::tablesExist()` no longer accepts a string. Use `Doctrine\DBAL\Schema\AbstractSchemaManager::tableExists()` instead. +- Method `Doctrine\DBAL\Schema\OracleSchemaManager::createDatabase()` no longer accepts `null` for `$database` argument. +- Removed unused method `Doctrine\DBAL\Schema\AbstractSchemaManager::_getPortableFunctionsList()` +- Removed unused method `Doctrine\DBAL\Schema\AbstractSchemaManager::_getPortableFunctionDefinition()` +- Removed unused method `Doctrine\DBAL\Schema\OracleSchemaManager::_getPortableFunctionDefinition()` +- Removed unused method `Doctrine\DBAL\Schema\SqliteSchemaManager::_getPortableTableIndexDefinition()` + +## BC BREAK: Changes in the `Doctrine\DBAL\Driver` API + +1. The `$username` and `$password` arguments of `::connect()` are no longer nullable. Use an empty string to indicate empty username or password. +2. The return value of `::getDatabase()` has been documented as nullable since some of the drivers allow establishing a connection without selecting a database. + +## BC BREAK: `Doctrine\DBAL\Driver::getName()` removed + +The `Doctrine\DBAL\Driver::getName()` has been removed. + +## BC BREAK Removed previously deprecated features + + * Removed `json_array` type and all associated hacks. + * Removed `Connection::TRANSACTION_*` constants. + * Removed `AbstractPlatform::DATE_INTERVAL_UNIT_*` and `AbstractPlatform::TRIM_*` constants. + * Removed `MysqlSessionInit` listener. + * Removed `MysqlPlatform::getCollationFieldDeclaration()`. + * Removed `AbstractPlatform::getIdentityColumnNullInsertSQL()`. + * Removed `Table::addUnnamedForeignKeyConstraint()` and `Table::addNamedForeignKeyConstraint()`. + * Removed `Table::renameColumn()`. + * Removed `SQLParserUtils::getPlaceholderPositions()`. + * Removed `LoggerChain::addLogger`. + * Removed `AbstractSchemaManager::getFilterSchemaAssetsExpression()`, `Configuration::getFilterSchemaAssetsExpression()` + and `Configuration::getFilterSchemaAssetsExpression()`. + * `SQLParserUtils::*_TOKEN` constants made private. + +## BC BREAK `Connection::ping()` returns `void`. + +`Connection::ping()` and `PingableConnection::ping()` no longer return a boolean value. They will throw an exception in case of failure. + +## BC BREAK User-provided `PDO` instance is no longer supported + +In order to share the same `PDO` instances between DBAL and other components, initialize the connection in DBAL and access it using `Connection::getWrappedConnection()->getWrappedConnection()`. + +## BC BREAK PostgreSqlPlatform ForeignKeyConstraint support for `feferred` misspelling removed + +`PostgreSqlPlatform::getAdvancedForeignKeyOptionsSQL()` had a typo in it in 2.x. Both the option name +`feferred` and `deferred` were supported in `2.x` but the misspelling was removed in 3.x. + +## BC BREAK `AbstractSchemaManager::extractDoctrineTypeFromComment()` changed, `::removeDoctrineTypeFromComment()` removed + +`AbstractSchemaManager::extractDoctrineTypeFromComment()` made `protected`. It takes the comment by reference, removes the type annotation from it and returns the extracted Doctrine type. + +## BC BREAK `::errorCode()` and `::errorInfo()` removed from `Connection` and `Statement` APIs + +The error information is available in `DriverException` trown in case of an error. + +## BC BREAK Changes in driver exceptions + +1. The `Doctrine\DBAL\Driver\DriverException::getErrorCode()` method is removed. In order to obtain the driver error code, please use `::getCode()`. +2. `Doctrine\DBAL\Driver\PDOException` no longer extends `PDOException`. +3. The value returned by `Doctrine\DBAL\Driver\PDOException::getSQLState()` no longer falls back to the driver error code. + +The method was used internally and is no longer needed. + +## BC BREAK `DB2SchemaManager::_getPortableForeignKeyRuleDef()` removed + +The method was used internally and is no longer needed. + +## BC BREAK `AbstractPlatform::get*Expression()` methods no loner accept integer values as arguments + +The following methods' arguments do not longer accept integer value: + +- the `$expression` argument in `::getCountExpression()`, +- the `$decimals` argument in `::getRoundExpression()`, +- the `$seconds` argument in `::getDateAddSecondsExpression()`, +- the `$seconds` argument in `::getDateSubSecondsExpression()`, +- the `$minutes` argument in `::getDateAddMinutesExpression()`, +- the `$minutes` argument in `::getDateSubMinutesExpression()`, +- the `$hours` argument in `::getDateAddHourExpression()`, +- the `$hours` argument in `::getDateAddHourExpression()`, +- the `$days` argument in `::getDateAddDaysExpression()`, +- the `$days` argument in `::getDateSubDaysExpression()`, +- the `$weeks` argument in `::getDateAddWeeksExpression()`, +- the `$weeks` argument in `::getDateSubWeeksExpression()`, +- the `$months` argument in `::getDateAddMonthExpression()`, +- the `$months` argument in `::getDateSubMonthExpression()`, +- the `$quarters` argument in `::getDateAddQuartersExpression()`, +- the `$quarters` argument in `::getDateSubQuartersExpression()`, +- the `$years` argument in `::getDateAddYearsExpression()`, +- the `$years` argument in `::getDateSubYearsExpression()`. + +Please use the strings representing numeric SQL literals instead (e.g. `'1'` instead of `1`). + +The signature of `AbstractPlatform::getConcatExpression()` changed to `::getConcatExpression(string ...$string)`. + +## BC BREAK The type of `$start` in `AbstractPlatform::getLocateExpression()` changed from `string|false` to `?string` + +The default value of `$start` is now `null`, not `false`. + +## BC BREAK The types of `$start` and `$length` in `AbstractPlatform::getSubstringExpression()` changed from `int` and `?int` to `string` and `?string` respectively + +The platform abstraction allows building arbitrary SQL expressions, so even if the arguments represent numeric literals, they should be passed as a string. + +## BC BREAK The type of `$char` in `AbstractPlatform::getTrimExpression()` changed from `string|false` to `?string` + +The default value of `$char` is now `null`, not `false`. Additionally, the method will throw an `InvalidArgumentException` in an invalid value of `$mode` is passed. + +## BC BREAK `Statement::quote()` only accepts strings. + +`Statement::quote()` and `ExpressionBuilder::literal()` no longer accept arguments of an arbitrary type and and don't implement type-specific handling. Only strings can be quoted. + +## BC BREAK `Statement` and `Connection` methods return `void`. + +`Connection::connect()`, `Statement::bindParam()`, `::bindValue()`, `::execute()`, `ResultStatement::setFetchMode()` and `::closeCursor()` no longer return a boolean value. They will throw an exception in case of failure. + +## BC BREAK `Statement::rowCount()` is moved. + +`Statement::rowCount()` has been moved to the `ResultStatement` interface where it belongs by definition. + +## BC BREAK Transaction-related `Statement` methods return `void`. + +`Statement::beginTransaction()`, `::commit()` and `::rollBack()` no longer return a boolean value. They will throw a `DriverException` in case of failure. + +## MINOR BC BREAK `Statement::fetchColumn()` with an invalid index. + +Similarly to `PDOStatement::fetchColumn()`, DBAL statements throw an exception in case of an invalid column index. + +## BC BREAK `Statement::execute()` with redundant parameters. + +Similarly to the drivers based on `pdo_pgsql` and `pdo_sqlsrv`, `OCI8Statement::execute()` and `MySQLiStatement::execute()` do not longer ignore redundant parameters. + +## BC BREAK: `Doctrine\DBAL\Types\Type::getDefaultLength()` removed + +The `Doctrine\DBAL\Types\Type::getDefaultLength()` method has been removed as it served no purpose. + +## BC BREAK: `Doctrine\DBAL\Types\Type::__toString()` removed + +Relying on string representation was discouraged and has been removed. + +## BC BREAK: The `NULL` value of `$offset` in LIMIT queries is not allowed + +The `NULL` value of the `$offset` argument in `AbstractPlatform::(do)?ModifyLimitQuery()` methods is no longer allowed. The absence of the offset should be indicated with a `0` which is now the default value. + +## BC BREAK: Removed dbal:import CLI command + +The `dbal:import` CLI command has been removed since it only worked with PDO-based drivers by relying on a non-documented behavior of the extension, and it was impossible to make it work with other drivers. +Please use other database client applications for import, e.g.: + + * For MySQL and MariaDB: `mysql [dbname] < data.sql`. + * For PostgreSQL: `psql [dbname] < data.sql`. + * For SQLite: `sqlite3 /path/to/file.db < data.sql`. + +## BC BREAK: Removed support for DB-generated UUIDs + +The support for DB-generated UUIDs was removed as non-portable. +Please generate UUIDs on the application side (e.g. using [ramsey/uuid](https://packagist.org/packages/ramsey/uuid)). + +## BC BREAK: Removed MsSQLKeywords class + +The `Doctrine\DBAL\Platforms\MsSQLKeywords` has been removed. +Please use `Doctrine\DBAL\Platforms\SQLServerPlatform `instead. + +## BC BREAK: Removed PDO DB2 driver + +This PDO-based IBM DB2 driver (built on top of pdo_ibm extension) has already been unsupported as of 2.5, it has now been now removed. + +The following class has been removed: + + * `Doctrine\DBAL\Driver\PDOIbm\Driver` + +## BC BREAK: Removed support for SQL Anywhere 12 and older + +DBAL now requires SQL Anywhere 16 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to newer SQL Anywhere version (16+). +`Doctrine\DBAL\Platforms\SQLAnywherePlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLAnywhereKeywords` now represent the SQL Anywhere 16. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\SQLAnywhere11Platform` + * `Doctrine\DBAL\Platforms\SQLAnywhere12Platform` + * `Doctrine\DBAL\Platforms\SQLAnywhere16Platform` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere11Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere12Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLAnywhere16Keywords` + +## BC BREAK: Removed support for SQL Server 2005 and older + +DBAL now requires SQL Server 2008 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to newer SQL Server version (2012+ is recommended). +`Doctrine\DBAL\Platforms\SQLServerPlatform` and `Doctrine\DBAL\Platforms\Keywords\SQLServerKeywords` now represent the SQL Server 2008. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\SQLServer2005Platform` + * `Doctrine\DBAL\Platforms\SQLServer2008Platform` + * `Doctrine\DBAL\Platforms\Keywords\SQLServer2005Keywords` + * `Doctrine\DBAL\Platforms\Keywords\SQLServer2008Keywords` + +## BC BREAK: Removed support for PostgreSQL 9.2 and older + +DBAL now requires PostgeSQL 9.3 or newer, support for unmaintained versions has been dropped. +If you are using any of the legacy versions, you have to upgrade to newer PostgreSQL version (9.6+ is recommended). +`Doctrine\DBAL\Platforms\PostgreSqlPlatform` and `Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords` now represent the PostgreSQL 9.3. + +The following classes have been removed: + + * `Doctrine\DBAL\Platforms\PostgreSQL91Platform` + * `Doctrine\DBAL\Platforms\PostgreSQL92Platform` + * `Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords` + * `Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords` + +## BC BREAK: Removed Doctrine\DBAL\Version + +The Doctrine\DBAL\Version class is no longer available: please refrain from checking the DBAL version at runtime. + +## BC BREAK: the PDO symbols are no longer part of the DBAL API + +1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed. +2. `\Doctrine\DBAL\Driver\PDOConnection` does not extend `\PDO` anymore. Please use `\Doctrine\DBAL\Driver\PDOConnection::getWrappedConnection()` to access the underlying `PDO` object. +3. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore. + +Before: + + use Doctrine\DBAL\Portability\Connection; + + $params = array( + 'wrapperClass' => Connection::class, + 'fetch_case' => PDO::CASE_LOWER, + ); + + $stmt->bindValue(1, 1, PDO::PARAM_INT); + $stmt->fetchAll(PDO::FETCH_COLUMN); + +After: + + use Doctrine\DBAL\ColumnCase; + use Doctrine\DBAL\FetchMode; + use Doctrine\DBAL\ParameterType; + use Doctrine\DBAL\Portability\Connection; + + $params = array( + 'wrapperClass' => Connection::class, + 'fetch_case' => ColumnCase::LOWER, + ); + + $stmt->bindValue(1, 1, ParameterType::INTEGER); + $stmt->fetchAll(FetchMode::COLUMN); + +## BC BREAK: Removed Drizzle support + +The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL anymore. + +## BC BREAK: SQLLogger changes + +- The `SQLLogger` interface has changed; the methods are the same but use scalar type hints, return types, and non-nullable arrays. +- `SQLLogger` implementations: `DebugStack`, `EchoSQLLogger`, `LoggerChain` are now final. +- `Configuration::getSQLLogger()` does not return `null` anymore, but a `NullLogger` implementation. +- `Configuration::setSQLLogger()` does not allow `null` anymore. + +## BC BREAK: Changes to handling binary fields + +- Binary fields whose length exceeds the maximum field size on a given platform are no longer represented as `BLOB`s. + Use binary fields of a size which fits all target platforms, or use blob explicitly instead. +- Binary fields are no longer represented as streams in PHP. They are represented as strings. + # Upgrade to 2.10 ## Deprecated `Doctrine\DBAL\Driver::getName()` diff --git a/bin/doctrine-dbal.php b/bin/doctrine-dbal.php index f3e064ffd62..76bed1a6701 100644 --- a/bin/doctrine-dbal.php +++ b/bin/doctrine-dbal.php @@ -1,5 +1,7 @@ `_ -- `SQL Anywhere 11.0.0 `_ -- `SQL Anywhere 11.0.1 `_ -- `SQL Anywhere 12.0.0 `_ -- `SQL Anywhere 12.0.1 `_ +You can find a list of supported connection parameters for the +currently supported platform here: + - `SAP Sybase SQL Anywhere 16.0 `_ Automatic platform version detection diff --git a/docs/en/reference/introduction.rst b/docs/en/reference/introduction.rst index ae495ea9815..5318303a7c6 100644 --- a/docs/en/reference/introduction.rst +++ b/docs/en/reference/introduction.rst @@ -21,7 +21,6 @@ The following database vendors are currently supported: - PostgreSQL - SAP Sybase SQL Anywhere - SQLite -- Drizzle The Doctrine 2 database layer can be used independently of the object-relational mapper. In order to use the DBAL all you need is diff --git a/docs/en/reference/platforms.rst b/docs/en/reference/platforms.rst index 32ef74304ea..12e292eec11 100644 --- a/docs/en/reference/platforms.rst +++ b/docs/en/reference/platforms.rst @@ -50,18 +50,15 @@ Oracle Microsoft SQL Server ^^^^^^^^^^^^^^^^^^^^ -- ``SQLServerPlatform`` for version 2000 and above. -- ``SQLServer2005Platform`` for version 2005 and above. -- ``SQLServer2008Platform`` for version 2008 and above. +- ``SQLServerPlatform`` for version 2008 and above. - ``SQLServer2012Platform`` for version 2012 and above. PostgreSQL ^^^^^^^^^^ - ``PostgreSqlPlatform`` for all versions. -- ``PostgreSQL91Platform`` for version 9.1 and above. -- ``PostgreSQL92Platform`` for version 9.2 and above. - ``PostgreSQL94Platform`` for version 9.4 and above. +- ``PostgreSQL100Platform`` for version 10.0 and above. SAP Sybase SQL Anywhere ^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,11 +73,6 @@ SQLite - ``SqlitePlatform`` for all versions. -Drizzle -^^^^^^ - -- ``DrizzlePlatform`` for all versions. - It is highly encouraged to use the platform class that matches your database vendor and version best. Otherwise it is not guaranteed that the compatibility in terms of SQL dialect and feature support diff --git a/docs/en/reference/schema-representation.rst b/docs/en/reference/schema-representation.rst index b250a5c5109..381a997e321 100644 --- a/docs/en/reference/schema-representation.rst +++ b/docs/en/reference/schema-representation.rst @@ -115,10 +115,10 @@ The following options are not completely portable but are supported by most of t vendors: - **unsigned** (boolean): Whether a ``smallint``, ``integer`` or ``bigint`` Doctrine - type column should allow unsigned values only. Supported by MySQL, SQL Anywhere - and Drizzle. Defaults to ``false``. + type column should allow unsigned values only. Supported by MySQL and SQL Anywhere. + Defaults to ``false``. - **comment** (integer|string): The column comment. Supported by MySQL, PostgreSQL, - Oracle, SQL Server, SQL Anywhere and Drizzle. Defaults to ``null``. + Oracle, SQL Server and SQL Anywhere. Defaults to ``null``. Vendor specific options ^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,8 +133,8 @@ The following options are completely vendor specific and absolutely not portable supported by some vendors but not portable: - **charset** (string): The character set to use for the column. Currently only supported - on MySQL and Drizzle. + on MySQL. - **collation** (string): The collation to use for the column. Supported by MySQL, PostgreSQL, - Sqlite, SQL Server and Drizzle. + Sqlite and SQL Server. - **check** (string): The check constraint clause to add to the column. Defaults to ``null``. diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index f4916a69672..dd733f33a51 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -517,8 +517,6 @@ Please also notice the mapping specific footnotes for additional information. +===================+===============+==========================+=========+==========================================================+ | **smallint** | ``integer`` | **MySQL** | *all* | ``SMALLINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``INT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``SMALLINT`` | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``NUMBER(5)`` | @@ -527,11 +525,9 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``SMALLINT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **integer** | ``integer`` | **MySQL** | *all* | ``INT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``INT`` [12]_ | | | | | +----------------------------------------------------------+ @@ -543,12 +539,10 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``INT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **bigint** | ``string`` | **MySQL** | *all* | ``BIGINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | [8]_ +--------------------------+ | | -| | | **Drizzle** | | | -| | +--------------------------+---------+----------------------------------------------------------+ +| | [8]_ +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``BIGINT`` [12]_ | | | | | +----------------------------------------------------------+ | | | | | ``BIGSERIAL`` [11]_ | @@ -559,7 +553,7 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``UNSIGNED`` [10]_ ``BIGINT`` ``IDENTITY`` [11]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [16]_ | +| | | **SQLite** | *all* | ``INTEGER`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **decimal** [7]_ | ``string`` | **MySQL** | *all* | ``NUMERIC(p, s)`` ``UNSIGNED`` [10]_ | | | [9]_ +--------------------------+---------+----------------------------------------------------------+ @@ -572,8 +566,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **float** | ``float`` | **MySQL** | *all* | ``DOUBLE PRECISION`` ``UNSIGNED`` [10]_ | | | +--------------------------+---------+----------------------------------------------------------+ @@ -586,8 +578,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **string** | ``string`` | **MySQL** | *all* | ``VARCHAR(n)`` [3]_ | | [2]_ [5]_ | +--------------------------+ | | @@ -597,8 +587,6 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``VARCHAR(n)`` | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``VARCHAR2(n)`` [3]_ | | | | | +----------------------------------------------------------+ | | | | | ``CHAR(n)`` [4]_ | @@ -607,19 +595,17 @@ Please also notice the mapping specific footnotes for additional information. | | | | +----------------------------------------------------------+ | | | | | ``NCHAR(n)`` [4]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -632,8 +618,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **Oracle** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``UNIQUEIDENTIFIER`` | | | +--------------------------+ | | @@ -647,27 +631,23 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+ | ``BINARY(n)`` [4]_ | | | | **SQL Anywhere** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Drizzle** | *all* | ``VARBINARY(n)`` | -| | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``RAW(n)`` | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BYTEA`` [16]_ | +| | | **PostgreSQL** | *all* | ``BYTEA`` [15]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``BLOB`` [16]_ | +| | | **SQLite** | *all* | ``BLOB`` [15]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [17]_ | +| **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``BLOB`` [18]_ | +| | | | | ``BLOB`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMBLOB`` [19]_ | +| | | | | ``MEDIUMBLOB`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGBLOB`` [20]_ | +| | | | | ``LONGBLOB`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``BLOB`` | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARBINARY(MAX)`` | | | +--------------------------+---------+----------------------------------------------------------+ @@ -680,8 +660,6 @@ Please also notice the mapping specific footnotes for additional information. | | | **PostgreSQL** | *all* | ``BOOLEAN`` | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``BIT`` | | | +--------------------------+ | | @@ -698,16 +676,10 @@ Please also notice the mapping specific footnotes for additional information. | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+ | -| | | **SQL Server** | >= 2008 | | -| | | +---------+----------------------------------------------------------+ -| | | | < 2008 | ``DATETIME`` [16]_ | +| | | **SQL Server** | "all" | | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | -| | +--------------------------+ +----------------------------------------------------------+ -| | | **Drizzle** | | ``TIMESTAMP`` [14]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``DATETIME`` | | | +--------------------------+ | | @@ -719,53 +691,41 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``TIMESTAMP(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [15]_ [16]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | +| **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [14]_ [15]_ | | | +--------------------------+ | | | | | **SQLite** | | | | | +--------------------------+---------+ | -| | | **SQL Server** | < 2008 | | -| | | +---------+----------------------------------------------------------+ -| | | | >= 2008 | ``DATETIMEOFFSET(6)`` | +| | | **SQL Server** | "all" | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITH TIME ZONE`` | | | +--------------------------+ | | | | | **Oracle** | | | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Anywhere** | < 12 | ``DATETIME`` [15]_ [16]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 12 | ``TIMESTAMP WITH TIME ZONE`` | +| | | **SQL Anywhere** | "all" | ``TIMESTAMP WITH TIME ZONE`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ | **time** | ``\DateTime`` | **MySQL** | *all* | ``TIME`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | | | +--------------------------+ | | | | | **SQLite** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TIME(0) WITHOUT TIME ZONE`` | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``DATE`` [16]_ | +| | | **Oracle** | *all* | ``DATE`` [15]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | < 2008 | ``DATETIME`` [16]_ | -| | | +---------+----------------------------------------------------------+ -| | | | >= 2008 | ``TIME(0)`` | +| | | **SQL Server** | "all" | ``TIME(0)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | +-------------------+ | | +----------------------------------------------------------+ -| **simple array** | | | | ``TEXT`` [18]_ | +| **simple array** | | | | ``TEXT`` [17]_ | | [1]_ | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -773,25 +733,21 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **json_array** | ``array`` | **MySQL** [1]_ | *all* | ``TINYTEXT`` [17]_ | +| **json_array** | ``array`` | **MySQL** [1]_ | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | < 9.2 | ``TEXT`` [1]_ | -| | | +---------+----------------------------------------------------------+ -| | | | < 9.4 | ``JSON`` | +| | | **PostgreSQL** | < 9.4 | ``JSON`` | | | | +---------+----------------------------------------------------------+ -| | | | >= 9.4 | ``JSON`` [21]_ | +| | | | >= 9.4 | ``JSON`` [20]_ | | | | | +----------------------------------------------------------+ -| | | | | ``JSONB`` [22]_ | +| | | | | ``JSONB`` [21]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Anywhere** | *all* | ``TEXT`` [1]_ | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` [1]_ | | | +--------------------------+ | | @@ -799,19 +755,17 @@ Please also notice the mapping specific footnotes for additional information. | | +--------------------------+---------+----------------------------------------------------------+ | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` [1]_ | +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **object** [1]_ | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [17]_ | +| **object** [1]_ | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | | | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [18]_ | +| | | | | ``TEXT`` [17]_ | | | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [19]_ | +| | | | | ``MEDIUMTEXT`` [18]_ | | | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [20]_ | +| | | | | ``LONGTEXT`` [19]_ | | | +--------------------------+---------+----------------------------------------------------------+ | | | **PostgreSQL** | *all* | ``TEXT`` | | | +--------------------------+ | | | | | **SQL Anywhere** | | | -| | +--------------------------+ | | -| | | **Drizzle** | | | | | +--------------------------+---------+----------------------------------------------------------+ | | | **Oracle** | *all* | ``CLOB`` | | | +--------------------------+ | | @@ -827,10 +781,10 @@ Please also notice the mapping specific footnotes for additional information. .. [4] Chosen if the column definition has the **fixed** attribute set to ``true``. .. [5] Silently maps to the vendor specific ``text`` type if the given **length** attribute for **n** exceeds the maximum length the related platform allows. If this is the case, please - see [16]_. + see [15]_. .. [6] Silently maps to the vendor specific ``blob`` type if the given **length** attribute for **n** exceeds the maximum length the related platform allows. If this is the case, please - see [16]_. + see [15]_. .. [7] **p** is the precision and **s** the scale set in the column definition. The precision defaults to ``10`` and the scale to ``0`` if not set. .. [8] Returns PHP ``string`` type value instead of ``integer`` because of maximum integer value @@ -842,22 +796,20 @@ Please also notice the mapping specific footnotes for additional information. .. [12] Chosen if the column definition has the **autoincrement** attribute set to ``false`` (default). .. [13] Chosen if the column definition does not contain the **version** option inside the **platformOptions** attribute array or is set to ``false`` which marks it as a non-locking information column. -.. [14] Chosen if the column definition contains the **version** option inside the **platformOptions** - attribute array and is set to ``true`` which marks it as a locking information column. -.. [15] Fallback type as the vendor does not support a native date time type with timezone information. +.. [14] Fallback type as the vendor does not support a native date time type with timezone information. This means that the timezone information gets lost when storing a value. -.. [16] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a +.. [15] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a native distinct data type for this mapping. Using this type with this vendor can therefore have implications on schema comparison (*online* vs *offline* schema) and PHP type safety (data conversion from database to PHP value) because it silently falls back to its appropriate Doctrine type. -.. [17] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. -.. [18] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. -.. [19] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. -.. [20] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. -.. [21] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** +.. [16] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. +.. [17] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. +.. [18] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. +.. [19] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. +.. [20] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** attribute array or is set to ``false``. -.. [22] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** +.. [21] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** attribute array and is set to ``true``. Detection of Database Types diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 449a220a2af..257f3a1ebf8 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -1,17 +1,21 @@ data); + $this->data = null; } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return $this->columnCount; } @@ -59,15 +63,25 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function rowCount() : int { - if ($arg2 !== null || $arg3 !== null) { - throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); + if ($this->data === null) { + return 0; } - $this->defaultFetchMode = $fetchMode; + return count($this->data); + } - return true; + /** + * {@inheritdoc} + */ + public function setFetchMode(int $fetchMode, ...$args) : void + { + if (count($args) > 0) { + throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode().'); + } + + $this->defaultFetchMode = $fetchMode; } /** @@ -83,7 +97,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { if (! isset($this->data[$this->num])) { return false; @@ -108,16 +122,18 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX return reset($row); } - throw new InvalidArgumentException('Invalid fetch-style given for fetching result.'); + throw new InvalidArgumentException( + sprintf('Invalid fetch mode given for fetching result, %d given.', $fetchMode) + ); } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $rows = []; - while ($row = $this->fetch($fetchMode)) { + while ($row = $this->fetch($fetchMode, ...$args)) { $rows[] = $row; } @@ -127,11 +143,18 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); - // TODO: verify that return false is the correct behavior - return $row[$columnIndex] ?? false; + if ($row === false) { + return false; + } + + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } } diff --git a/lib/Doctrine/DBAL/Cache/CacheException.php b/lib/Doctrine/DBAL/Cache/CacheException.php index 636c948a616..787e02f12e3 100644 --- a/lib/Doctrine/DBAL/Cache/CacheException.php +++ b/lib/Doctrine/DBAL/Cache/CacheException.php @@ -1,24 +1,11 @@ lifetime = $lifetime; $this->cacheKey = $cacheKey; $this->resultCacheDriver = $resultCache; } - /** - * @return Cache|null - */ - public function getResultCacheDriver() + public function getResultCacheDriver() : ?Cache { return $this->resultCacheDriver; } - /** - * @return int - */ - public function getLifetime() + public function getLifetime() : int { return $this->lifetime; } /** - * @return string - * * @throws CacheException */ - public function getCacheKey() + public function getCacheKey() : string { if ($this->cacheKey === null) { - throw CacheException::noCacheKey(); + throw NoCacheKey::new(); } return $this->cacheKey; @@ -67,14 +58,13 @@ public function getCacheKey() /** * Generates the real cache key from query, params, types and connection parameters. * - * @param string $query * @param mixed[] $params * @param int[]|string[] $types * @param mixed[] $connectionParams * * @return string[] */ - public function generateCacheKeys($query, $params, $types, array $connectionParams = []) + public function generateCacheKeys(string $query, array $params, array $types, array $connectionParams = []) : array { $realCacheKey = 'query=' . $query . '¶ms=' . serialize($params) . @@ -91,30 +81,17 @@ public function generateCacheKeys($query, $params, $types, array $connectionPara return [$cacheKey, $realCacheKey]; } - /** - * @return \Doctrine\DBAL\Cache\QueryCacheProfile - */ - public function setResultCacheDriver(Cache $cache) + public function setResultCacheDriver(Cache $cache) : self { return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache); } - /** - * @param string|null $cacheKey - * - * @return \Doctrine\DBAL\Cache\QueryCacheProfile - */ - public function setCacheKey($cacheKey) + public function setCacheKey(?string $cacheKey) : self { return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCacheDriver); } - /** - * @param int $lifetime - * - * @return \Doctrine\DBAL\Cache\QueryCacheProfile - */ - public function setLifetime($lifetime) + public function setLifetime(int $lifetime) : self { return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCacheDriver); } diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index 8fbae62de29..4eb342022ce 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -1,18 +1,20 @@ statement = $stmt; $this->resultCache = $resultCache; @@ -75,11 +72,12 @@ public function __construct(ResultStatement $stmt, Cache $resultCache, $cacheKey /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { $this->statement->closeCursor(); + if (! $this->emptied || $this->data === null) { - return true; + return; } $data = $this->resultCache->fetch($this->cacheKey); @@ -90,14 +88,12 @@ public function closeCursor() $this->resultCache->save($this->cacheKey, $data, $this->lifetime); unset($this->data); - - return true; } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return $this->statement->columnCount(); } @@ -105,11 +101,9 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; - - return true; } /** @@ -125,7 +119,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { if ($this->data === null) { $this->data = []; @@ -165,9 +159,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { - $this->data = $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs); + $this->data = $this->statement->fetchAll($fetchMode, ...$args); $this->emptied = true; return $this->data; @@ -176,12 +170,19 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); - // TODO: verify that return false is the correct behavior - return $row[$columnIndex] ?? false; + if ($row === false) { + return false; + } + + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** @@ -195,10 +196,8 @@ public function fetchColumn($columnIndex = 0) * * @return int The number of rows. */ - public function rowCount() + public function rowCount() : int { - assert($this->statement instanceof Statement); - return $this->statement->rowCount(); } } diff --git a/lib/Doctrine/DBAL/ColumnCase.php b/lib/Doctrine/DBAL/ColumnCase.php index 872d3ede873..0edede03348 100644 --- a/lib/Doctrine/DBAL/ColumnCase.php +++ b/lib/Doctrine/DBAL/ColumnCase.php @@ -1,8 +1,8 @@ _attributes['sqlLogger'] = $logger; } /** * Gets the SQL logger that is used. - * - * @return SQLLogger|null */ - public function getSQLLogger() + public function getSQLLogger() : SQLLogger { - return $this->_attributes['sqlLogger'] ?? null; + return $this->_attributes['sqlLogger'] ?? $this->_attributes['sqlLogger'] = new NullLogger(); } /** * Gets the cache driver implementation that is used for query result caching. - * - * @return Cache|null */ - public function getResultCacheImpl() + public function getResultCacheImpl() : ?Cache { return $this->_attributes['resultCacheImpl'] ?? null; } /** * Sets the cache driver implementation that is used for query result caching. - * - * @return void */ - public function setResultCacheImpl(Cache $cacheImpl) + public function setResultCacheImpl(Cache $cacheImpl) : void { $this->_attributes['resultCacheImpl'] = $cacheImpl; } @@ -71,12 +66,8 @@ public function setResultCacheImpl(Cache $cacheImpl) * {AbstractSchemaManager#createSchema()}. * * @deprecated Use Configuration::setSchemaAssetsFilter() instead - * - * @param string $filterExpression - * - * @return void */ - public function setFilterSchemaAssetsExpression($filterExpression) + public function setFilterSchemaAssetsExpression(?string $filterExpression) : void { $this->_attributes['filterSchemaAssetsExpression'] = $filterExpression; if ($filterExpression) { @@ -86,29 +77,14 @@ public function setFilterSchemaAssetsExpression($filterExpression) } } - /** - * Returns filter schema assets expression. - * - * @deprecated Use Configuration::getSchemaAssetsFilter() instead - * - * @return string|null - */ - public function getFilterSchemaAssetsExpression() - { - return $this->_attributes['filterSchemaAssetsExpression'] ?? null; - } - - /** - * @param string $filterExpression - */ - private function buildSchemaAssetsFilterFromExpression($filterExpression) : callable + private function buildSchemaAssetsFilterFromExpression(string $filterExpression) : callable { - return static function ($assetName) use ($filterExpression) { + return static function ($assetName) use ($filterExpression) : bool { if ($assetName instanceof AbstractAsset) { $assetName = $assetName->getName(); } - return preg_match($filterExpression, $assetName); + return preg_match($filterExpression, $assetName) > 0; }; } @@ -137,13 +113,13 @@ public function getSchemaAssetsFilter() : ?callable * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either * the method commit or the method rollback. By default, new connections are in auto-commit mode. * - * @see getAutoCommit + * @see getAutoCommit * * @param bool $autoCommit True to enable auto-commit mode; false to disable it. */ - public function setAutoCommit($autoCommit) + public function setAutoCommit(bool $autoCommit) : void { - $this->_attributes['autoCommit'] = (bool) $autoCommit; + $this->_attributes['autoCommit'] = $autoCommit; } /** @@ -153,7 +129,7 @@ public function setAutoCommit($autoCommit) * * @return bool True if auto-commit mode is enabled by default for connections, false otherwise. */ - public function getAutoCommit() + public function getAutoCommit() : bool { return $this->_attributes['autoCommit'] ?? true; } diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index d514557ff79..d5d94a83f96 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -1,19 +1,29 @@ */ private $params = []; @@ -172,10 +153,10 @@ class Connection implements DriverConnection /** * Initializes a new instance of the Connection class. * - * @param mixed[] $params The connection parameters. - * @param Driver $driver The driver to use. - * @param Configuration|null $config The configuration, optional. - * @param EventManager|null $eventManager The event manager, optional. + * @param array $params The connection parameters. + * @param Driver $driver The driver to use. + * @param Configuration|null $config The configuration, optional. + * @param EventManager|null $eventManager The event manager, optional. * * @throws DBALException */ @@ -188,15 +169,9 @@ public function __construct( $this->_driver = $driver; $this->params = $params; - if (isset($params['pdo'])) { - $this->_conn = $params['pdo']; - $this->isConnected = true; - unset($this->params['pdo']); - } - if (isset($params['platform'])) { if (! $params['platform'] instanceof Platforms\AbstractPlatform) { - throw DBALException::invalidPlatformType($params['platform']); + throw InvalidPlatformType::new($params['platform']); } $this->platform = $params['platform']; @@ -222,89 +197,41 @@ public function __construct( /** * Gets the parameters used during instantiation. * - * @return mixed[] + * @return array */ - public function getParams() + public function getParams() : array { return $this->params; } /** * Gets the name of the database this Connection is connected to. - * - * @return string */ - public function getDatabase() + public function getDatabase() : ?string { return $this->_driver->getDatabase($this); } - /** - * Gets the hostname of the currently connected database. - * - * @return string|null - */ - public function getHost() - { - return $this->params['host'] ?? null; - } - - /** - * Gets the port of the currently connected database. - * - * @return mixed - */ - public function getPort() - { - return $this->params['port'] ?? null; - } - - /** - * Gets the username used by this connection. - * - * @return string|null - */ - public function getUsername() - { - return $this->params['user'] ?? null; - } - - /** - * Gets the password used by this connection. - * - * @return string|null - */ - public function getPassword() - { - return $this->params['password'] ?? null; - } - /** * Gets the DBAL driver instance. - * - * @return Driver */ - public function getDriver() + public function getDriver() : Driver { return $this->_driver; } /** * Gets the Configuration used by the Connection. - * - * @return Configuration */ - public function getConfiguration() + public function getConfiguration() : Configuration { return $this->_config; } /** * Gets the EventManager used by the Connection. - * - * @return EventManager */ - public function getEventManager() + public function getEventManager() : EventManager { return $this->_eventManager; } @@ -312,11 +239,9 @@ public function getEventManager() /** * Gets the DatabasePlatform for the connection. * - * @return AbstractPlatform - * * @throws DBALException */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { if ($this->platform === null) { $this->detectDatabasePlatform(); @@ -327,10 +252,8 @@ public function getDatabasePlatform() /** * Gets the ExpressionBuilder for the connection. - * - * @return ExpressionBuilder */ - public function getExpressionBuilder() + public function getExpressionBuilder() : ExpressionBuilder { return $this->_expr; } @@ -338,18 +261,17 @@ public function getExpressionBuilder() /** * Establishes the connection with the database. * - * @return bool TRUE if the connection was successfully established, FALSE if - * the connection is already open. + * @throws DriverException */ - public function connect() + public function connect() : void { if ($this->isConnected) { - return false; + return; } $driverOptions = $this->params['driverOptions'] ?? []; - $user = $this->params['user'] ?? null; - $password = $this->params['password'] ?? null; + $user = $this->params['user'] ?? ''; + $password = $this->params['password'] ?? ''; $this->_conn = $this->_driver->connect($this->params, $user, $password, $driverOptions); $this->isConnected = true; @@ -358,12 +280,12 @@ public function connect() $this->beginTransaction(); } - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new Event\ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new Event\ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** @@ -373,7 +295,7 @@ public function connect() * * @throws DBALException If an invalid platform was specified for this connection. */ - private function detectDatabasePlatform() + private function detectDatabasePlatform() : void { $version = $this->getDatabasePlatformVersion(); @@ -396,11 +318,9 @@ private function detectDatabasePlatform() * or the underlying driver connection cannot determine the platform * version without having to query it (performance reasons). * - * @return string|null - * * @throws Exception */ - private function getDatabasePlatformVersion() + private function getDatabasePlatformVersion() : ?string { // Driver does not support version specific platforms. if (! $this->_driver instanceof VersionAwarePlatformDriver) { @@ -453,10 +373,8 @@ private function getDatabasePlatformVersion() /** * Returns the database server version if the underlying driver supports it. - * - * @return string|null */ - private function getServerVersion() + private function getServerVersion() : ?string { $connection = $this->getWrappedConnection(); @@ -476,9 +394,9 @@ private function getServerVersion() * * @return bool True if auto-commit mode is currently enabled for this connection, false otherwise. */ - public function isAutoCommit() + public function isAutoCommit() : bool { - return $this->autoCommit === true; + return $this->autoCommit; } /** @@ -491,14 +409,13 @@ public function isAutoCommit() * NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is * committed. If this method is called and the auto-commit mode is not changed, the call is a no-op. * - * @see isAutoCommit + * @see isAutoCommit * - * @param bool $autoCommit True to enable auto-commit mode; false to disable it. + * @throws ConnectionException + * @throws DriverException */ - public function setAutoCommit($autoCommit) + public function setAutoCommit(bool $autoCommit) : void { - $autoCommit = (bool) $autoCommit; - // Mode not changed, no-op. if ($autoCommit === $this->autoCommit) { return; @@ -507,7 +424,7 @@ public function setAutoCommit($autoCommit) $this->autoCommit = $autoCommit; // Commit all currently active transactions if any when switching auto-commit mode. - if ($this->isConnected !== true || $this->transactionNestingLevel === 0) { + if (! $this->isConnected || $this->transactionNestingLevel === 0) { return; } @@ -516,12 +433,8 @@ public function setAutoCommit($autoCommit) /** * Sets the fetch mode. - * - * @param int $fetchMode - * - * @return void */ - public function setFetchMode($fetchMode) + public function setFetchMode(int $fetchMode) : void { $this->defaultFetchMode = $fetchMode; } @@ -530,58 +443,58 @@ public function setFetchMode($fetchMode) * Prepares and executes an SQL query and returns the first row of the result * as an associative array. * - * @param string $statement The SQL query. - * @param mixed[] $params The query parameters. - * @param int[]|string[] $types The query parameter types. + * @param string $query The SQL query. + * @param array|array $params The prepared statement params. + * @param array|array $types The query parameter types. * - * @return mixed[]|false False is returned if no rows are found. + * @return array|false False is returned if no rows are found. * * @throws DBALException */ - public function fetchAssoc($statement, array $params = [], array $types = []) + public function fetchAssoc(string $query, array $params = [], array $types = []) { - return $this->executeQuery($statement, $params, $types)->fetch(FetchMode::ASSOCIATIVE); + return $this->executeQuery($query, $params, $types)->fetch(FetchMode::ASSOCIATIVE); } /** * Prepares and executes an SQL query and returns the first row of the result * as a numerically indexed array. * - * @param string $statement The SQL query to be executed. - * @param mixed[] $params The prepared statement params. - * @param int[]|string[] $types The query parameter types. + * @param string $query The SQL query to be executed. + * @param array|array $params The prepared statement params. + * @param array|array $types The query parameter types. * - * @return mixed[]|false False is returned if no rows are found. + * @return array|false False is returned if no rows are found. + * + * @throws DBALException */ - public function fetchArray($statement, array $params = [], array $types = []) + public function fetchArray(string $query, array $params = [], array $types = []) { - return $this->executeQuery($statement, $params, $types)->fetch(FetchMode::NUMERIC); + return $this->executeQuery($query, $params, $types)->fetch(FetchMode::NUMERIC); } /** * Prepares and executes an SQL query and returns the value of a single column * of the first row of the result. * - * @param string $statement The SQL query to be executed. - * @param mixed[] $params The prepared statement params. - * @param int $column The 0-indexed column number to retrieve. - * @param int[]|string[] $types The query parameter types. + * @param string $query The SQL query to be executed. + * @param array|array $params The prepared statement params. + * @param int $column The 0-indexed column number to retrieve. + * @param array|array $types The query parameter types. * * @return mixed|false False is returned if no rows are found. * * @throws DBALException */ - public function fetchColumn($statement, array $params = [], $column = 0, array $types = []) + public function fetchColumn(string $query, array $params = [], int $column = 0, array $types = []) { - return $this->executeQuery($statement, $params, $types)->fetchColumn($column); + return $this->executeQuery($query, $params, $types)->fetchColumn($column); } /** * Whether an actual connection to the database is established. - * - * @return bool */ - public function isConnected() + public function isConnected() : bool { return $this->isConnected; } @@ -591,7 +504,7 @@ public function isConnected() * * @return bool TRUE if a transaction is currently active, FALSE otherwise. */ - public function isTransactionActive() + public function isTransactionActive() : bool { return $this->transactionNestingLevel > 0; } @@ -599,10 +512,10 @@ public function isTransactionActive() /** * Adds identifier condition to the query components * - * @param mixed[] $identifier Map of key columns to their values - * @param string[] $columns Column names - * @param mixed[] $values Column values - * @param string[] $conditions Key conditions + * @param array $identifier Map of key columns to their values + * @param array $columns Column names + * @param array $values Column values + * @param array $conditions Key conditions * * @throws DBALException */ @@ -631,19 +544,19 @@ private function addIdentifierCondition( * * Table expression and columns are not escaped and are not safe for user-input. * - * @param string $tableExpression The expression of the table on which to delete. - * @param mixed[] $identifier The deletion criteria. An associative array containing column-value pairs. - * @param int[]|string[] $types The types of identifiers. + * @param string $table The SQL expression of the table on which to delete. + * @param array $identifier The deletion criteria. An associative array containing column-value pairs. + * @param array|array $types The query parameter types. * * @return int The number of affected rows. * * @throws DBALException * @throws InvalidArgumentException */ - public function delete($tableExpression, array $identifier, array $types = []) + public function delete(string $table, array $identifier, array $types = []) : int { if (empty($identifier)) { - throw InvalidArgumentException::fromEmptyCriteria(); + throw EmptyCriteriaNotAllowed::new(); } $columns = $values = $conditions = []; @@ -651,7 +564,7 @@ public function delete($tableExpression, array $identifier, array $types = []) $this->addIdentifierCondition($identifier, $columns, $values, $conditions); return $this->executeUpdate( - 'DELETE FROM ' . $tableExpression . ' WHERE ' . implode(' AND ', $conditions), + 'DELETE FROM ' . $table . ' WHERE ' . implode(' AND ', $conditions), $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types ); @@ -659,10 +572,8 @@ public function delete($tableExpression, array $identifier, array $types = []) /** * Closes the connection. - * - * @return void */ - public function close() + public function close() : void { $this->_conn = null; @@ -673,14 +584,12 @@ public function close() * Sets the transaction isolation level. * * @param int $level The level to set. - * - * @return int */ - public function setTransactionIsolation($level) + public function setTransactionIsolation(int $level) : void { $this->transactionIsolationLevel = $level; - return $this->executeUpdate($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level)); + $this->executeUpdate($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level)); } /** @@ -688,7 +597,7 @@ public function setTransactionIsolation($level) * * @return int The current transaction isolation level. */ - public function getTransactionIsolation() + public function getTransactionIsolation() : int { if ($this->transactionIsolationLevel === null) { $this->transactionIsolationLevel = $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel(); @@ -702,16 +611,16 @@ public function getTransactionIsolation() * * Table expression and columns are not escaped and are not safe for user-input. * - * @param string $tableExpression The expression of the table to update quoted or unquoted. - * @param mixed[] $data An associative array containing column-value pairs. - * @param mixed[] $identifier The update criteria. An associative array containing column-value pairs. - * @param int[]|string[] $types Types of the merged $data and $identifier arrays in that order. + * @param string $table The SQL expression of the table to update quoted or unquoted. + * @param array $data An associative array containing column-value pairs. + * @param array $identifier The update criteria. An associative array containing column-value pairs. + * @param array|array $types The query parameter types. * * @return int The number of affected rows. * * @throws DBALException */ - public function update($tableExpression, array $data, array $identifier, array $types = []) + public function update(string $table, array $data, array $identifier, array $types = []) : int { $columns = $values = $conditions = $set = []; @@ -727,7 +636,7 @@ public function update($tableExpression, array $data, array $identifier, array $ $types = $this->extractTypeValues($columns, $types); } - $sql = 'UPDATE ' . $tableExpression . ' SET ' . implode(', ', $set) + $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $set) . ' WHERE ' . implode(' AND ', $conditions); return $this->executeUpdate($sql, $values, $types); @@ -738,18 +647,18 @@ public function update($tableExpression, array $data, array $identifier, array $ * * Table expression and columns are not escaped and are not safe for user-input. * - * @param string $tableExpression The expression of the table to insert data into, quoted or unquoted. - * @param mixed[] $data An associative array containing column-value pairs. - * @param int[]|string[] $types Types of the inserted data. + * @param string $table The SQL expression of the table to insert data into, quoted or unquoted. + * @param array $data An associative array containing column-value pairs. + * @param array|array $types The query parameter types. * * @return int The number of affected rows. * * @throws DBALException */ - public function insert($tableExpression, array $data, array $types = []) + public function insert(string $table, array $data, array $types = []) : int { if (empty($data)) { - return $this->executeUpdate('INSERT INTO ' . $tableExpression . ' () VALUES ()'); + return $this->executeUpdate('INSERT INTO ' . $table . ' () VALUES ()'); } $columns = []; @@ -763,7 +672,7 @@ public function insert($tableExpression, array $data, array $types = []) } return $this->executeUpdate( - 'INSERT INTO ' . $tableExpression . ' (' . implode(', ', $columns) . ')' . + 'INSERT INTO ' . $table . ' (' . implode(', ', $columns) . ')' . ' VALUES (' . implode(', ', $set) . ')', $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types @@ -773,16 +682,16 @@ public function insert($tableExpression, array $data, array $types = []) /** * Extract ordered type list from an ordered column list and type map. * - * @param int[]|string[] $columnList - * @param int[]|string[] $types + * @param array $columnList + * @param array $types The query parameter types. * - * @return int[]|string[] + * @return array|array */ private function extractTypeValues(array $columnList, array $types) { $typeValues = []; - foreach ($columnList as $columnIndex => $columnName) { + foreach ($columnList as $columnName) { $typeValues[] = $types[$columnName] ?? ParameterType::STRING; } @@ -799,56 +708,50 @@ private function extractTypeValues(array $columnList, array $types) * you SHOULD use them. In general, they end up causing way more * problems than they solve. * - * @param string $str The name to be quoted. + * @param string $identifier The identifier to be quoted. * - * @return string The quoted name. + * @return string The quoted identifier. */ - public function quoteIdentifier($str) + public function quoteIdentifier(string $identifier) : string { - return $this->getDatabasePlatform()->quoteIdentifier($str); + return $this->getDatabasePlatform()->quoteIdentifier($identifier); } /** * {@inheritDoc} */ - public function quote($input, $type = null) + public function quote(string $input) : string { - $connection = $this->getWrappedConnection(); - - [$value, $bindingType] = $this->getBindingInfo($input, $type); - - return $connection->quote($value, $bindingType); + return $this->getWrappedConnection()->quote($input); } /** * Prepares and executes an SQL query and returns the result as an associative array. * - * @param string $sql The SQL query. - * @param mixed[] $params The query parameters. - * @param int[]|string[] $types The query parameter types. + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. * - * @return mixed[] + * @return array */ - public function fetchAll($sql, array $params = [], $types = []) + public function fetchAll(string $query, array $params = [], array $types = []) : array { - return $this->executeQuery($sql, $params, $types)->fetchAll(); + return $this->executeQuery($query, $params, $types)->fetchAll(); } /** * Prepares an SQL statement. * - * @param string $statement The SQL statement to prepare. - * - * @return DriverStatement The prepared statement. + * @param string $sql The SQL statement to prepare. * * @throws DBALException */ - public function prepare($statement) + public function prepare(string $sql) : DriverStatement { try { - $stmt = new Statement($statement, $this); + $stmt = new Statement($sql, $this); } catch (Throwable $ex) { - throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); + throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } $stmt->setFetchMode($this->defaultFetchMode); @@ -862,16 +765,16 @@ public function prepare($statement) * If the query is parametrized, a prepared statement is used. * If an SQLLogger is configured, the execution is logged. * - * @param string $query The SQL query to execute. - * @param mixed[] $params The parameters to bind to the query, if any. - * @param int[]|string[] $types The types the previous parameters are in. - * @param QueryCacheProfile|null $qcp The query cache profile, optional. + * @param string $query The SQL query to execute. + * @param array|array $params The parameters to bind to the query, if any. + * @param array|array $types The query parameter types. + * @param QueryCacheProfile|null $qcp The query cache profile, optional. * * @return ResultStatement The executed statement. * * @throws DBALException */ - public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement { if ($qcp !== null) { return $this->executeCacheQuery($query, $params, $types, $qcp); @@ -880,9 +783,7 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($query, $params, $types); - } + $logger->startQuery($query, $params, $types); try { if ($params) { @@ -904,9 +805,7 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach $stmt->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $stmt; } @@ -914,21 +813,19 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach /** * Executes a caching query. * - * @param string $query The SQL query to execute. - * @param mixed[] $params The parameters to bind to the query, if any. - * @param int[]|string[] $types The types the previous parameters are in. - * @param QueryCacheProfile $qcp The query cache profile. - * - * @return ResultStatement + * @param string $query The SQL query to execute. + * @param array|array $params The parameters to bind to the query, if any. + * @param array|array $types The query parameter types. + * @param QueryCacheProfile $qcp The query cache profile. * * @throws CacheException */ - public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) + public function executeCacheQuery(string $query, array $params, array $types, QueryCacheProfile $qcp) : ResultStatement { $resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl(); if ($resultCache === null) { - throw CacheException::noResultDriverConfigured(); + throw NoResultDriverConfigured::new(); } $connectionParams = $this->getParams(); @@ -961,15 +858,15 @@ public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qc * Executes an, optionally parametrized, SQL query and returns the result, * applying a given projection/transformation function on each row of the result. * - * @param string $query The SQL query to execute. - * @param mixed[] $params The parameters, if any. - * @param Closure $function The transformation function that is applied on each row. - * The function receives a single parameter, an array, that - * represents a row of the result set. + * @param string $query The SQL query to execute. + * @param array|array $params The parameters, if any. + * @param Closure $function The transformation function that is applied on each row. + * The function receives a single parameter, an array, that + * represents a row of the result set. * - * @return mixed[] The projected result of the query. + * @return array The projected result of the query. */ - public function project($query, array $params, Closure $function) + public function project(string $query, array $params, Closure $function) : array { $result = []; $stmt = $this->executeQuery($query, $params); @@ -984,34 +881,24 @@ public function project($query, array $params, Closure $function) } /** - * Executes an SQL statement, returning a result set as a Statement object. - * - * @return \Doctrine\DBAL\Driver\Statement - * - * @throws DBALException + * {@inheritDoc} */ - public function query() + public function query(string $sql) : ResultStatement { $connection = $this->getWrappedConnection(); - $args = func_get_args(); - $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($args[0]); - } + $logger->startQuery($sql); try { - $statement = $connection->query(...$args); + $statement = $connection->query($sql); } catch (Throwable $ex) { - throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); + throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } $statement->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $statement; } @@ -1022,22 +909,18 @@ public function query() * * This method supports PDO binding types as well as DBAL mapping types. * - * @param string $query The SQL query. - * @param mixed[] $params The query parameters. - * @param int[]|string[] $types The parameter types. - * - * @return int The number of affected rows. + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. * * @throws DBALException */ - public function executeUpdate($query, array $params = [], array $types = []) + public function executeUpdate(string $query, array $params = [], array $types = []) : int { $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($query, $params, $types); - } + $logger->startQuery($query, $params, $types); try { if ($params) { @@ -1059,30 +942,20 @@ public function executeUpdate($query, array $params = [], array $types = []) throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); } - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $result; } /** - * Executes an SQL statement and return the number of affected rows. - * - * @param string $statement - * - * @return int The number of affected rows. - * - * @throws DBALException + * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); - if ($logger) { - $logger->startQuery($statement); - } + $logger->startQuery($statement); try { $result = $connection->exec($statement); @@ -1090,9 +963,7 @@ public function exec($statement) throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); } - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $result; } @@ -1102,29 +973,11 @@ public function exec($statement) * * @return int The nesting level. A value of 0 means there's no active transaction. */ - public function getTransactionNestingLevel() + public function getTransactionNestingLevel() : int { return $this->transactionNestingLevel; } - /** - * Fetches the SQLSTATE associated with the last database operation. - * - * @return string|null The last error code. - */ - public function errorCode() - { - return $this->getWrappedConnection()->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->getWrappedConnection()->errorInfo(); - } - /** * Returns the ID of the last inserted row, or the last value from a sequence object, * depending on the underlying driver. @@ -1133,13 +986,13 @@ public function errorInfo() * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY * columns or sequences. * - * @param string|null $seqName Name of the sequence object from which the ID should be returned. + * @param string|null $name Name of the sequence object from which the ID should be returned. * * @return string A string representation of the last inserted ID. */ - public function lastInsertId($seqName = null) + public function lastInsertId(?string $name = null) : string { - return $this->getWrappedConnection()->lastInsertId($seqName); + return $this->getWrappedConnection()->lastInsertId($name); } /** @@ -1154,7 +1007,6 @@ public function lastInsertId($seqName = null) * * @return mixed The value returned by $func * - * @throws Exception * @throws Throwable */ public function transactional(Closure $func) @@ -1165,9 +1017,6 @@ public function transactional(Closure $func) $this->commit(); return $res; - } catch (Exception $e) { - $this->rollBack(); - throw $e; } catch (Throwable $e) { $this->rollBack(); throw $e; @@ -1177,31 +1026,25 @@ public function transactional(Closure $func) /** * Sets if nested transactions should use savepoints. * - * @param bool $nestTransactionsWithSavepoints - * - * @return void - * * @throws ConnectionException */ - public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints) + public function setNestTransactionsWithSavepoints(bool $nestTransactionsWithSavepoints) : void { if ($this->transactionNestingLevel > 0) { - throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction(); + throw MayNotAlterNestedTransactionWithSavepointsInTransaction::new(); } if (! $this->getDatabasePlatform()->supportsSavepoints()) { - throw ConnectionException::savepointsNotSupported(); + throw SavepointsNotSupported::new(); } - $this->nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints; + $this->nestTransactionsWithSavepoints = $nestTransactionsWithSavepoints; } /** * Gets if nested transactions should use savepoints. - * - * @return bool */ - public function getNestTransactionsWithSavepoints() + public function getNestTransactionsWithSavepoints() : bool { return $this->nestTransactionsWithSavepoints; } @@ -1220,7 +1063,7 @@ protected function _getNestedTransactionSavePointName() /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { $connection = $this->getWrappedConnection(); @@ -1229,26 +1072,18 @@ public function beginTransaction() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"START TRANSACTION"'); - } - - $connection->beginTransaction(); + $logger->startQuery('"START TRANSACTION"'); - if ($logger) { + try { + $connection->beginTransaction(); + } finally { $logger->stopQuery(); } } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"SAVEPOINT"'); - } + $logger->startQuery('"SAVEPOINT"'); $this->createSavepoint($this->_getNestedTransactionSavePointName()); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } - - return true; } /** @@ -1257,13 +1092,13 @@ public function beginTransaction() * @throws ConnectionException If the commit failed due to no active transaction or * because the transaction was marked for rollback only. */ - public function commit() + public function commit() : void { if ($this->transactionNestingLevel === 0) { - throw ConnectionException::noActiveTransaction(); + throw NoActiveTransaction::new(); } if ($this->isRollbackOnly) { - throw ConnectionException::commitFailedRollbackOnly(); + throw CommitFailedRollbackOnly::new(); } $connection = $this->getWrappedConnection(); @@ -1271,40 +1106,35 @@ public function commit() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"COMMIT"'); - } + $logger->startQuery('"COMMIT"'); - $connection->commit(); - - if ($logger) { + try { + $connection->commit(); + } finally { $logger->stopQuery(); } } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"RELEASE SAVEPOINT"'); - } + $logger->startQuery('"RELEASE SAVEPOINT"'); $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } --$this->transactionNestingLevel; if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) { - return true; + return; } $this->beginTransaction(); - - return true; } /** * Commits all current nesting transactions. + * + * @throws ConnectionException + * @throws DriverException */ - private function commitAll() + private function commitAll() : void { while ($this->transactionNestingLevel !== 0) { if ($this->autoCommit === false && $this->transactionNestingLevel === 1) { @@ -1320,14 +1150,14 @@ private function commitAll() } /** - * Cancels any database changes done during the current transaction. + * {@inheritDoc} * * @throws ConnectionException If the rollback operation failed. */ - public function rollBack() + public function rollBack() : void { if ($this->transactionNestingLevel === 0) { - throw ConnectionException::noActiveTransaction(); + throw NoActiveTransaction::new(); } $connection = $this->getWrappedConnection(); @@ -1335,28 +1165,24 @@ public function rollBack() $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { - if ($logger) { - $logger->startQuery('"ROLLBACK"'); - } + $logger->startQuery('"ROLLBACK"'); $this->transactionNestingLevel = 0; - $connection->rollBack(); - $this->isRollbackOnly = false; - if ($logger) { + + try { + $connection->rollBack(); + } finally { + $this->isRollbackOnly = false; $logger->stopQuery(); - } - if ($this->autoCommit === false) { - $this->beginTransaction(); + if ($this->autoCommit === false) { + $this->beginTransaction(); + } } } elseif ($this->nestTransactionsWithSavepoints) { - if ($logger) { - $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); - } + $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); --$this->transactionNestingLevel; - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); } else { $this->isRollbackOnly = true; --$this->transactionNestingLevel; @@ -1368,14 +1194,12 @@ public function rollBack() * * @param string $savepoint The name of the savepoint to create. * - * @return void - * * @throws ConnectionException */ - public function createSavepoint($savepoint) + public function createSavepoint(string $savepoint) : void { if (! $this->getDatabasePlatform()->supportsSavepoints()) { - throw ConnectionException::savepointsNotSupported(); + throw SavepointsNotSupported::new(); } $this->getWrappedConnection()->exec($this->platform->createSavePoint($savepoint)); @@ -1386,14 +1210,12 @@ public function createSavepoint($savepoint) * * @param string $savepoint The name of the savepoint to release. * - * @return void - * * @throws ConnectionException */ - public function releaseSavepoint($savepoint) + public function releaseSavepoint(string $savepoint) : void { if (! $this->getDatabasePlatform()->supportsSavepoints()) { - throw ConnectionException::savepointsNotSupported(); + throw SavepointsNotSupported::new(); } if (! $this->platform->supportsReleaseSavepoints()) { @@ -1408,14 +1230,12 @@ public function releaseSavepoint($savepoint) * * @param string $savepoint The name of the savepoint to rollback to. * - * @return void - * * @throws ConnectionException */ - public function rollbackSavepoint($savepoint) + public function rollbackSavepoint(string $savepoint) : void { if (! $this->getDatabasePlatform()->supportsSavepoints()) { - throw ConnectionException::savepointsNotSupported(); + throw SavepointsNotSupported::new(); } $this->getWrappedConnection()->exec($this->platform->rollbackSavePoint($savepoint)); @@ -1423,10 +1243,8 @@ public function rollbackSavepoint($savepoint) /** * Gets the wrapped driver connection. - * - * @return DriverConnection */ - public function getWrappedConnection() + public function getWrappedConnection() : DriverConnection { $this->connect(); @@ -1436,10 +1254,8 @@ public function getWrappedConnection() /** * Gets the SchemaManager that can be used to inspect or change the * database schema through the connection. - * - * @return AbstractSchemaManager */ - public function getSchemaManager() + public function getSchemaManager() : AbstractSchemaManager { if ($this->_schemaManager === null) { $this->_schemaManager = $this->_driver->getSchemaManager($this); @@ -1452,14 +1268,12 @@ public function getSchemaManager() * Marks the current transaction so that the only possible * outcome for the transaction to be rolled back. * - * @return void - * * @throws ConnectionException If no transaction is active. */ - public function setRollbackOnly() + public function setRollbackOnly() : void { if ($this->transactionNestingLevel === 0) { - throw ConnectionException::noActiveTransaction(); + throw NoActiveTransaction::new(); } $this->isRollbackOnly = true; } @@ -1467,14 +1281,12 @@ public function setRollbackOnly() /** * Checks whether the current transaction is marked for rollback only. * - * @return bool - * * @throws ConnectionException If no transaction is active. */ - public function isRollbackOnly() + public function isRollbackOnly() : bool { if ($this->transactionNestingLevel === 0) { - throw ConnectionException::noActiveTransaction(); + throw NoActiveTransaction::new(); } return $this->isRollbackOnly; @@ -1489,7 +1301,7 @@ public function isRollbackOnly() * * @return mixed The converted value. */ - public function convertToDatabaseValue($value, $type) + public function convertToDatabaseValue($value, string $type) { return Type::getType($type)->convertToDatabaseValue($value, $this->getDatabasePlatform()); } @@ -1503,7 +1315,7 @@ public function convertToDatabaseValue($value, $type) * * @return mixed The converted type. */ - public function convertToPHPValue($value, $type) + public function convertToPHPValue($value, string $type) { return Type::getType($type)->convertToPHPValue($value, $this->getDatabasePlatform()); } @@ -1515,13 +1327,11 @@ public function convertToPHPValue($value, $type) * @internal Duck-typing used on the $stmt parameter to support driver statements as well as * raw PDOStatement instances. * - * @param \Doctrine\DBAL\Driver\Statement $stmt The statement to bind the values to. - * @param mixed[] $params The map/list of named/positional parameters. - * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). - * - * @return void + * @param DriverStatement $stmt The statement to bind the values to. + * @param array|array $params The map/list of named/positional parameters. + * @param array|array $types The query parameter types. */ - private function _bindTypedValues($stmt, array $params, array $types) + private function _bindTypedValues(DriverStatement $stmt, array $params, array $types) : void { // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. if (is_int(key($params))) { @@ -1559,9 +1369,9 @@ private function _bindTypedValues($stmt, array $params, array $types) * @param mixed $value The value to bind. * @param int|string|null $type The type to bind (PDO or DBAL). * - * @return mixed[] [0] => the (escaped) value, [1] => the binding type. + * @return array [0] => the (escaped) value, [1] => the binding type. */ - private function getBindingInfo($value, $type) + private function getBindingInfo($value, $type) : array { if (is_string($type)) { $type = Type::getType($type); @@ -1582,12 +1392,12 @@ private function getBindingInfo($value, $type) * @internal This is a purely internal method. If you rely on this method, you are advised to * copy/paste the code as this method may change, or be removed without prior notice. * - * @param mixed[] $params - * @param int[]|string[] $types + * @param array|array $params + * @param array|array $types The query parameter types. * - * @return mixed[] + * @return array|array */ - public function resolveParams(array $params, array $types) + public function resolveParams(array $params, array $types) : array { $resolvedParams = []; @@ -1625,10 +1435,8 @@ public function resolveParams(array $params, array $types) /** * Creates a new instance of a SQL query builder. - * - * @return QueryBuilder */ - public function createQueryBuilder() + public function createQueryBuilder() : QueryBuilder { return new Query\QueryBuilder($this); } @@ -1636,38 +1444,40 @@ public function createQueryBuilder() /** * Ping the server * - * When the server is not available the method returns FALSE. + * When the server is not available the method throws a DBALException. * It is responsibility of the developer to handle this case - * and abort the request or reconnect manually: + * and abort the request or close the connection so that it's reestablished + * upon the next statement execution. * - * @return bool + * @throws DBALException * * @example * - * if ($conn->ping() === false) { + * try { + * $conn->ping(); + * } catch (DBALException $e) { * $conn->close(); - * $conn->connect(); * } * * It is undefined if the underlying driver attempts to reconnect * or disconnect when the connection is not available anymore - * as long it returns TRUE when a reconnect succeeded and - * FALSE when the connection was dropped. + * as long it successfully returns when a reconnect succeeded + * and throws an exception if the connection was dropped. */ - public function ping() + public function ping() : void { $connection = $this->getWrappedConnection(); - if ($connection instanceof PingableConnection) { - return $connection->ping(); + if (! $connection instanceof PingableConnection) { + $this->query($this->getDatabasePlatform()->getDummySelectSQL()); + + return; } try { - $this->query($this->getDatabasePlatform()->getDummySelectSQL()); - - return true; - } catch (DBALException $e) { - return false; + $connection->ping(); + } catch (DriverException $e) { + throw DBALException::driverException($this->_driver, $e); } } } diff --git a/lib/Doctrine/DBAL/ConnectionException.php b/lib/Doctrine/DBAL/ConnectionException.php index d3d11bc6743..c7051042929 100644 --- a/lib/Doctrine/DBAL/ConnectionException.php +++ b/lib/Doctrine/DBAL/ConnectionException.php @@ -1,38 +1,9 @@ */ protected $connections = ['master' => null, 'slave' => null]; @@ -86,12 +90,16 @@ class MasterSlaveConnection extends Connection /** * Creates Master Slave Connection. * - * @param mixed[] $params + * @param array $params * * @throws InvalidArgumentException */ - public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null) - { + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { if (! isset($params['slaves'], $params['master'])) { throw new InvalidArgumentException('master or slaves configuration missing'); } @@ -111,10 +119,8 @@ public function __construct(array $params, Driver $driver, ?Configuration $confi /** * Checks if the connection is currently towards the master or not. - * - * @return bool */ - public function isConnectedToMaster() + public function isConnectedToMaster() : bool { return $this->_conn !== null && $this->_conn === $this->connections['master']; } @@ -122,7 +128,7 @@ public function isConnectedToMaster() /** * {@inheritDoc} */ - public function connect($connectionName = null) + public function connect($connectionName = null) : void { $requestedConnectionChange = ($connectionName !== null); $connectionName = $connectionName ?: 'slave'; @@ -135,7 +141,7 @@ public function connect($connectionName = null) // change request, then abort right here, because we are already done. // This prevents writes to the slave in case of "keepSlave" option enabled. if ($this->_conn !== null && ! $requestedConnectionChange) { - return false; + return; } $forceMasterAsSlave = false; @@ -152,7 +158,7 @@ public function connect($connectionName = null) $this->connections['slave'] = $this->_conn; } - return false; + return; } if ($connectionName === 'master') { @@ -166,22 +172,18 @@ public function connect($connectionName = null) $this->connections['slave'] = $this->_conn = $this->connectTo($connectionName); } - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** * Connects to a specific connection. - * - * @param string $connectionName - * - * @return DriverConnection */ - protected function connectTo($connectionName) + protected function connectTo(string $connectionName) : DriverConnection { $params = $this->getParams(); @@ -189,19 +191,18 @@ protected function connectTo($connectionName) $connectionParams = $this->chooseConnectionConfiguration($connectionName, $params); - $user = $connectionParams['user'] ?? null; - $password = $connectionParams['password'] ?? null; + $user = $connectionParams['user'] ?? ''; + $password = $connectionParams['password'] ?? ''; return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); } /** - * @param string $connectionName - * @param mixed[] $params + * @param array $params * - * @return mixed + * @return array */ - protected function chooseConnectionConfiguration($connectionName, $params) + protected function chooseConnectionConfiguration(string $connectionName, array $params) : array { if ($connectionName === 'master') { return $params['master']; @@ -219,7 +220,7 @@ protected function chooseConnectionConfiguration($connectionName, $params) /** * {@inheritDoc} */ - public function executeUpdate($query, array $params = [], array $types = []) + public function executeUpdate(string $query, array $params = [], array $types = []) : int { $this->connect('master'); @@ -229,47 +230,47 @@ public function executeUpdate($query, array $params = [], array $types = []) /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->connect('master'); - return parent::beginTransaction(); + parent::beginTransaction(); } /** * {@inheritDoc} */ - public function commit() + public function commit() : void { $this->connect('master'); - return parent::commit(); + parent::commit(); } /** * {@inheritDoc} */ - public function rollBack() + public function rollBack() : void { $this->connect('master'); - return parent::rollBack(); + parent::rollBack(); } /** * {@inheritDoc} */ - public function delete($tableName, array $identifier, array $types = []) + public function delete(string $table, array $identifier, array $types = []) : int { $this->connect('master'); - return parent::delete($tableName, $identifier, $types); + return parent::delete($table, $identifier, $types); } /** * {@inheritDoc} */ - public function close() + public function close() : void { unset($this->connections['master'], $this->connections['slave']); @@ -282,27 +283,27 @@ public function close() /** * {@inheritDoc} */ - public function update($tableName, array $data, array $identifier, array $types = []) + public function update(string $table, array $data, array $identifier, array $types = []) : int { $this->connect('master'); - return parent::update($tableName, $data, $identifier, $types); + return parent::update($table, $data, $identifier, $types); } /** * {@inheritDoc} */ - public function insert($tableName, array $data, array $types = []) + public function insert(string $table, array $data, array $types = []) : int { $this->connect('master'); - return parent::insert($tableName, $data, $types); + return parent::insert($table, $data, $types); } /** * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $this->connect('master'); @@ -312,7 +313,7 @@ public function exec($statement) /** * {@inheritDoc} */ - public function createSavepoint($savepoint) + public function createSavepoint(string $savepoint) : void { $this->connect('master'); @@ -322,7 +323,7 @@ public function createSavepoint($savepoint) /** * {@inheritDoc} */ - public function releaseSavepoint($savepoint) + public function releaseSavepoint(string $savepoint) : void { $this->connect('master'); @@ -332,7 +333,7 @@ public function releaseSavepoint($savepoint) /** * {@inheritDoc} */ - public function rollbackSavepoint($savepoint) + public function rollbackSavepoint(string $savepoint) : void { $this->connect('master'); @@ -342,25 +343,19 @@ public function rollbackSavepoint($savepoint) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) : ResultStatement { $this->connect('master'); assert($this->_conn instanceof DriverConnection); - $args = func_get_args(); - $logger = $this->getConfiguration()->getSQLLogger(); - if ($logger) { - $logger->startQuery($args[0]); - } + $logger->startQuery($sql); - $statement = $this->_conn->query(...$args); + $statement = $this->_conn->query($sql); $statement->setFetchMode($this->defaultFetchMode); - if ($logger) { - $logger->stopQuery(); - } + $logger->stopQuery(); return $statement; } @@ -368,10 +363,10 @@ public function query() /** * {@inheritDoc} */ - public function prepare($statement) + public function prepare(string $sql) : Statement { $this->connect('master'); - return parent::prepare($statement); + return parent::prepare($sql); } } diff --git a/lib/Doctrine/DBAL/DBALException.php b/lib/Doctrine/DBAL/DBALException.php index 4961af2f35f..65141360304 100644 --- a/lib/Doctrine/DBAL/DBALException.php +++ b/lib/Doctrine/DBAL/DBALException.php @@ -1,163 +1,52 @@ getMessage() ); - } - - /** - * Returns a new instance for an invalid specified platform version. - * - * @param string $version The invalid platform version given. - * @param string $expectedFormat The expected platform version format. - * - * @return DBALException - */ - public static function invalidPlatformVersionSpecified($version, $expectedFormat) - { - return new self( - sprintf( - 'Invalid platform version "%s" specified. ' . - 'The platform version has to be specified in the format: "%s".', - $version, - $expectedFormat - ) - ); - } - - /** - * @return \Doctrine\DBAL\DBALException - */ - public static function invalidPdoInstance() - { - return new self( - "The 'pdo' option was used in DriverManager::getConnection() but no " . - 'instance of PDO was given.' - ); - } - /** - * @param string|null $url The URL that was provided in the connection parameters (if any). - * - * @return \Doctrine\DBAL\DBALException - */ - public static function driverRequired($url = null) - { - if ($url) { - return new self( - sprintf( - "The options 'driver' or 'driverClass' are mandatory if a connection URL without scheme " . - 'is given to DriverManager::getConnection(). Given URL: %s', - $url - ) - ); - } - - return new self("The options 'driver' or 'driverClass' are mandatory if no PDO " . - 'instance is given to DriverManager::getConnection().'); + return static::wrapException($driver, $driverEx, $message); } - /** - * @param string $unknownDriverName - * @param string[] $knownDrivers - * - * @return \Doctrine\DBAL\DBALException - */ - public static function unknownDriver($unknownDriverName, array $knownDrivers) + public static function driverException(Driver $driver, Throwable $driverEx) : self { - return new self("The given 'driver' " . $unknownDriverName . ' is unknown, ' . - 'Doctrine currently supports only the following drivers: ' . implode(', ', $knownDrivers)); + return static::wrapException($driver, $driverEx, sprintf('An exception occurred in driver with message: %s', $driverEx->getMessage())); } - /** - * @param string $sql - * @param mixed[] $params - * - * @return self - */ - public static function driverExceptionDuringQuery(Driver $driver, Throwable $driverEx, $sql, array $params = []) - { - $msg = "An exception occurred while executing '" . $sql . "'"; - if ($params) { - $msg .= ' with params ' . self::formatParameters($params); - } - $msg .= ":\n\n" . $driverEx->getMessage(); - - return static::wrapException($driver, $driverEx, $msg); - } - - /** - * @return self - */ - public static function driverException(Driver $driver, Throwable $driverEx) - { - return static::wrapException($driver, $driverEx, 'An exception occurred in driver: ' . $driverEx->getMessage()); - } - - /** - * @return self - */ - private static function wrapException(Driver $driver, Throwable $driverEx, $msg) + private static function wrapException(Driver $driver, Throwable $driverEx, string $msg) : self { if ($driverEx instanceof DriverException) { return $driverEx; @@ -173,13 +62,11 @@ private static function wrapException(Driver $driver, Throwable $driverEx, $msg) * Returns a human-readable representation of an array of parameters. * This properly handles binary data by returning a hex representation. * - * @param mixed[] $params - * - * @return string + * @param array $params */ - private static function formatParameters(array $params) + private static function formatParameters(array $params) : string { - return '[' . implode(', ', array_map(static function ($param) { + return '[' . implode(', ', array_map(static function ($param) : string { if (is_resource($param)) { return (string) $param; } @@ -194,101 +81,4 @@ private static function formatParameters(array $params) return $json; }, $params)) . ']'; } - - /** - * @param string $wrapperClass - * - * @return \Doctrine\DBAL\DBALException - */ - public static function invalidWrapperClass($wrapperClass) - { - return new self("The given 'wrapperClass' " . $wrapperClass . ' has to be a ' . - 'subtype of \Doctrine\DBAL\Connection.'); - } - - /** - * @param string $driverClass - * - * @return \Doctrine\DBAL\DBALException - */ - public static function invalidDriverClass($driverClass) - { - return new self("The given 'driverClass' " . $driverClass . ' has to implement the ' . Driver::class . ' interface.'); - } - - /** - * @param string $tableName - * - * @return \Doctrine\DBAL\DBALException - */ - public static function invalidTableName($tableName) - { - return new self('Invalid table name specified: ' . $tableName); - } - - /** - * @param string $tableName - * - * @return \Doctrine\DBAL\DBALException - */ - public static function noColumnsSpecifiedForTable($tableName) - { - return new self('No columns specified for table ' . $tableName); - } - - /** - * @return \Doctrine\DBAL\DBALException - */ - public static function limitOffsetInvalid() - { - return new self('Invalid Offset in Limit Query, it has to be larger than or equal to 0.'); - } - - /** - * @param string $name - * - * @return \Doctrine\DBAL\DBALException - */ - public static function typeExists($name) - { - return new self('Type ' . $name . ' already exists.'); - } - - /** - * @param string $name - * - * @return \Doctrine\DBAL\DBALException - */ - public static function unknownColumnType($name) - { - return new self('Unknown column type "' . $name . '" requested. Any Doctrine type that you use has ' . - 'to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the ' . - 'known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database ' . - 'introspection then you might have forgotten to register all database types for a Doctrine Type. Use ' . - 'AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement ' . - 'Type#getMappedDatabaseTypes(). If the type name is empty you might ' . - 'have a problem with the cache or forgot some mapping information.'); - } - - /** - * @param string $name - * - * @return \Doctrine\DBAL\DBALException - */ - public static function typeNotFound($name) - { - return new self('Type to be overwritten ' . $name . ' does not exist.'); - } - - public static function typeNotRegistered(Type $type) : self - { - return new self(sprintf('Type of the class %s@%s is not registered.', get_class($type), spl_object_hash($type))); - } - - public static function typeAlreadyRegistered(Type $type) : self - { - return new self( - sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type)) - ); - } } diff --git a/lib/Doctrine/DBAL/Driver.php b/lib/Doctrine/DBAL/Driver.php index 8a80d4a428a..0cfc18cbba1 100644 --- a/lib/Doctrine/DBAL/Driver.php +++ b/lib/Doctrine/DBAL/Driver.php @@ -1,7 +1,10 @@ getParams(); @@ -25,7 +29,7 @@ public function getDatabase(Connection $conn) /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { return new DB2Platform(); } @@ -33,7 +37,7 @@ public function getDatabasePlatform() /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new DB2SchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractDriverException.php b/lib/Doctrine/DBAL/Driver/AbstractDriverException.php index d9af92d1744..5f217f22dc2 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractDriverException.php +++ b/lib/Doctrine/DBAL/Driver/AbstractDriverException.php @@ -1,21 +1,17 @@ errorCode = $errorCode; - $this->sqlState = $sqlState; - } - - /** - * {@inheritdoc} - */ - public function getErrorCode() - { - return $this->errorCode; + $this->sqlState = $sqlState; } /** * {@inheritdoc} */ - public function getSQLState() + public function getSQLState() : ?string { return $this->sqlState; } diff --git a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php index c46ddc63dd7..fada4ed9e4a 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php @@ -1,15 +1,22 @@ getErrorCode()) { - case '1213': + switch ($exception->getCode()) { + case 1213: return new Exception\DeadlockException($message, $exception); - case '1205': + case 1205: return new Exception\LockWaitTimeoutException($message, $exception); - case '1050': + case 1050: return new Exception\TableExistsException($message, $exception); - case '1051': - case '1146': + case 1051: + case 1146: return new Exception\TableNotFoundException($message, $exception); - case '1216': - case '1217': - case '1451': - case '1452': - case '1701': + case 1216: + case 1217: + case 1451: + case 1452: + case 1701: return new Exception\ForeignKeyConstraintViolationException($message, $exception); - case '1062': - case '1557': - case '1569': - case '1586': + case 1062: + case 1557: + case 1569: + case 1586: return new Exception\UniqueConstraintViolationException($message, $exception); - case '1054': - case '1166': - case '1611': + case 1054: + case 1166: + case 1611: return new Exception\InvalidFieldNameException($message, $exception); - case '1052': - case '1060': - case '1110': + case 1052: + case 1060: + case 1110: return new Exception\NonUniqueFieldNameException($message, $exception); - case '1064': - case '1149': - case '1287': - case '1341': - case '1342': - case '1343': - case '1344': - case '1382': - case '1479': - case '1541': - case '1554': - case '1626': + case 1064: + case 1149: + case 1287: + case 1341: + case 1342: + case 1343: + case 1344: + case 1382: + case 1479: + case 1541: + case 1554: + case 1626: return new Exception\SyntaxErrorException($message, $exception); - case '1044': - case '1045': - case '1046': - case '1049': - case '1095': - case '1142': - case '1143': - case '1227': - case '1370': - case '1429': - case '2002': - case '2005': + case 1044: + case 1045: + case 1046: + case 1049: + case 1095: + case 1142: + case 1143: + case 1227: + case 1370: + case 1429: + case 2002: + case 2005: return new Exception\ConnectionException($message, $exception); - case '1048': - case '1121': - case '1138': - case '1171': - case '1252': - case '1263': - case '1364': - case '1566': + case 1048: + case 1121: + case 1138: + case 1171: + case 1252: + case 1263: + case 1364: + case 1566: return new Exception\NotNullConstraintViolationException($message, $exception); } - return new Exception\DriverException($message, $exception); + return new DriverException($message, $exception); } /** @@ -111,7 +118,7 @@ public function convertException($message, DriverException $exception) * * @throws DBALException */ - public function createDatabasePlatformForVersion($version) + public function createDatabasePlatformForVersion(string $version) : AbstractPlatform { $mariadb = stripos($version, 'mariadb') !== false; if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) { @@ -146,7 +153,7 @@ private function getOracleMysqlVersionNumber(string $versionString) : string $versionString, $versionParts )) { - throw DBALException::invalidPlatformVersionSpecified( + throw InvalidPlatformVersion::new( $versionString, '..' ); @@ -177,7 +184,7 @@ private function getMariaDbMysqlVersionNumber(string $versionString) : string $versionString, $versionParts )) { - throw DBALException::invalidPlatformVersionSpecified( + throw InvalidPlatformVersion::new( $versionString, '^(?:5\.5\.5-)?(mariadb-)?..' ); @@ -189,7 +196,7 @@ private function getMariaDbMysqlVersionNumber(string $versionString) : string /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); @@ -201,7 +208,7 @@ public function getDatabase(Connection $conn) * * @return MySqlPlatform */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { return new MySqlPlatform(); } @@ -211,7 +218,7 @@ public function getDatabasePlatform() * * @return MySqlSchemaManager */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new MySqlSchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php b/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php index dcbaaf097f7..17e04bbf937 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php @@ -1,12 +1,18 @@ getErrorCode()) { - case '1': - case '2299': - case '38911': + switch ($exception->getCode()) { + case 1: + case 2299: + case 38911: return new Exception\UniqueConstraintViolationException($message, $exception); - case '904': + case 904: return new Exception\InvalidFieldNameException($message, $exception); - case '918': - case '960': + case 918: + case 960: return new Exception\NonUniqueFieldNameException($message, $exception); - case '923': + case 923: return new Exception\SyntaxErrorException($message, $exception); - case '942': + case 942: return new Exception\TableNotFoundException($message, $exception); - case '955': + case 955: return new Exception\TableExistsException($message, $exception); - case '1017': - case '12545': + case 1017: + case 12545: return new Exception\ConnectionException($message, $exception); - case '1400': + case 1400: return new Exception\NotNullConstraintViolationException($message, $exception); - case '2266': - case '2291': - case '2292': + case 2266: + case 2291: + case 2292: return new Exception\ForeignKeyConstraintViolationException($message, $exception); } - return new Exception\DriverException($message, $exception); + return new DriverException($message, $exception); } /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); @@ -70,7 +76,7 @@ public function getDatabase(Connection $conn) /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { return new OraclePlatform(); } @@ -78,7 +84,7 @@ public function getDatabasePlatform() /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new OracleSchemaManager($conn); } @@ -87,10 +93,8 @@ public function getSchemaManager(Connection $conn) * Returns an appropriate Easy Connect String for the given parameters. * * @param mixed[] $params The connection parameters to return the Easy Connect String for. - * - * @return string */ - protected function getEasyConnectString(array $params) + protected function getEasyConnectString(array $params) : string { return (string) EasyConnectString::fromConnectionParameters($params); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php index 916d924980c..933837e166c 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php @@ -1,16 +1,20 @@ getSQLState()) { case '40001': @@ -64,28 +68,25 @@ public function convertException($message, DriverException $exception) case '42P07': return new Exception\TableExistsException($message, $exception); + } - case '7': - // In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code. - // The exception code is always set to 7 here. - // We have to match against the SQLSTATE in the error message in these cases. - if (strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { - return new Exception\ConnectionException($message, $exception); - } - - break; + // In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code. + // The exception code is always set to 7 here. + // We have to match against the SQLSTATE in the error message in these cases. + if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { + return new Exception\ConnectionException($message, $exception); } - return new Exception\DriverException($message, $exception); + return new DriverException($message, $exception); } /** * {@inheritdoc} */ - public function createDatabasePlatformForVersion($version) + public function createDatabasePlatformForVersion(string $version) : AbstractPlatform { if (! preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts)) { - throw DBALException::invalidPlatformVersionSpecified( + throw InvalidPlatformVersion::new( $version, '..' ); @@ -101,10 +102,6 @@ public function createDatabasePlatformForVersion($version) return new PostgreSQL100Platform(); case version_compare($version, '9.4', '>='): return new PostgreSQL94Platform(); - case version_compare($version, '9.2', '>='): - return new PostgreSQL92Platform(); - case version_compare($version, '9.1', '>='): - return new PostgreSQL91Platform(); default: return new PostgreSqlPlatform(); } @@ -113,7 +110,7 @@ public function createDatabasePlatformForVersion($version) /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); @@ -123,7 +120,7 @@ public function getDatabase(Connection $conn) /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { return new PostgreSqlPlatform(); } @@ -131,7 +128,7 @@ public function getDatabasePlatform() /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new PostgreSqlSchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php index 88f26ce7def..248c0cfbd2f 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php @@ -1,19 +1,21 @@ getErrorCode()) { - case '-306': - case '-307': - case '-684': + switch ($exception->getCode()) { + case -306: + case -307: + case -684: return new Exception\DeadlockException($message, $exception); - case '-210': - case '-1175': - case '-1281': + case -210: + case -1175: + case -1281: return new Exception\LockWaitTimeoutException($message, $exception); - case '-100': - case '-103': - case '-832': + case -100: + case -103: + case -832: return new Exception\ConnectionException($message, $exception); - case '-143': + case -143: return new Exception\InvalidFieldNameException($message, $exception); - case '-193': - case '-196': + case -193: + case -196: return new Exception\UniqueConstraintViolationException($message, $exception); - case '-194': - case '-198': + case -194: + case -198: return new Exception\ForeignKeyConstraintViolationException($message, $exception); - case '-144': + case -144: return new Exception\NonUniqueFieldNameException($message, $exception); - case '-184': - case '-195': + case -184: + case -195: return new Exception\NotNullConstraintViolationException($message, $exception); - case '-131': + case -131: return new Exception\SyntaxErrorException($message, $exception); - case '-110': + case -110: return new Exception\TableExistsException($message, $exception); - case '-141': - case '-1041': + case -141: + case -1041: return new Exception\TableNotFoundException($message, $exception); } - return new Exception\DriverException($message, $exception); + return new DriverException($message, $exception); } /** * {@inheritdoc} */ - public function createDatabasePlatformForVersion($version) + public function createDatabasePlatformForVersion(string $version) : AbstractPlatform { if (! preg_match( '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', $version, $versionParts )) { - throw DBALException::invalidPlatformVersionSpecified( + throw InvalidPlatformVersion::new( $version, '...' ); } - $majorVersion = $versionParts['major']; - $minorVersion = $versionParts['minor'] ?? 0; - $patchVersion = $versionParts['patch'] ?? 0; - $buildVersion = $versionParts['build'] ?? 0; - $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; - switch (true) { - case version_compare($version, '16', '>='): - return new SQLAnywhere16Platform(); - case version_compare($version, '12', '>='): - return new SQLAnywhere12Platform(); - case version_compare($version, '11', '>='): - return new SQLAnywhere11Platform(); default: return new SQLAnywherePlatform(); } @@ -102,7 +92,7 @@ public function createDatabasePlatformForVersion($version) /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); @@ -112,15 +102,15 @@ public function getDatabase(Connection $conn) /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { - return new SQLAnywhere12Platform(); + return new SQLAnywherePlatform(); } /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new SQLAnywhereSchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php index 421d82b3951..4fd6d1442a4 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php @@ -1,14 +1,16 @@ \d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', $version, $versionParts )) { - throw DBALException::invalidPlatformVersionSpecified( + throw InvalidPlatformVersion::new( $version, '...' ); @@ -44,10 +46,6 @@ public function createDatabasePlatformForVersion($version) switch (true) { case version_compare($version, '11.00.2100', '>='): return new SQLServer2012Platform(); - case version_compare($version, '10.00.1600', '>='): - return new SQLServer2008Platform(); - case version_compare($version, '9.00.1399', '>='): - return new SQLServer2005Platform(); default: return new SQLServerPlatform(); } @@ -56,7 +54,7 @@ public function createDatabasePlatformForVersion($version) /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); @@ -66,15 +64,15 @@ public function getDatabase(Connection $conn) /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { - return new SQLServer2008Platform(); + return new SQLServerPlatform(); } /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new SQLServerSchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php b/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php index 582f7cae20a..760e9a0ca33 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php @@ -1,11 +1,17 @@ getMessage(), 'database is locked') !== false) { return new Exception\LockWaitTimeoutException($message, $exception); @@ -67,23 +73,23 @@ public function convertException($message, DriverException $exception) return new Exception\ConnectionException($message, $exception); } - return new Exception\DriverException($message, $exception); + return new DriverException($message, $exception); } /** * {@inheritdoc} */ - public function getDatabase(Connection $conn) + public function getDatabase(Connection $conn) : ?string { $params = $conn->getParams(); - return $params['path'] ?? null; + return $params['path'] ?? ''; } /** * {@inheritdoc} */ - public function getDatabasePlatform() + public function getDatabasePlatform() : AbstractPlatform { return new SqlitePlatform(); } @@ -91,7 +97,7 @@ public function getDatabasePlatform() /** * {@inheritdoc} */ - public function getSchemaManager(Connection $conn) + public function getSchemaManager(Connection $conn) : AbstractSchemaManager { return new SqliteSchemaManager($conn); } diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 1574581c2ad..89402cfd7f9 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -1,8 +1,10 @@ constructPdoDsn($params), - $username, - $password, - $driverOptions - ); - } - - /** - * {@inheritdoc} - */ - public function createDatabasePlatformForVersion($version) - { - return $this->getDatabasePlatform(); - } - - /** - * {@inheritdoc} - */ - public function getDatabasePlatform() - { - return new DrizzlePlatform(); - } - - /** - * {@inheritdoc} - */ - public function getSchemaManager(\Doctrine\DBAL\Connection $conn) - { - return new DrizzleSchemaManager($conn); - } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'drizzle_pdo_mysql'; - } -} diff --git a/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php b/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php index 9b79e240c4e..2ce84676064 100644 --- a/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php +++ b/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php @@ -1,7 +1,12 @@ $params + * @param array $driverOptions * * @throws DB2Exception */ - public function __construct(array $params, $username, $password, $driverOptions = []) + public function __construct(array $params, string $username, string $password, array $driverOptions = []) { - $isPersistent = (isset($params['persistent']) && $params['persistent'] === true); - - if ($isPersistent) { + if (isset($params['persistent']) && $params['persistent'] === true) { $conn = db2_pconnect($params['dbname'], $username, $password, $driverOptions); } else { $conn = db2_connect($params['dbname'], $username, $password, $driverOptions); } if ($conn === false) { - throw new DB2Exception(db2_conn_errormsg()); + throw DB2Exception::fromConnectionError(); } $this->conn = $conn; @@ -57,7 +52,7 @@ public function __construct(array $params, $username, $password, $driverOptions /** * {@inheritdoc} */ - public function getServerVersion() + public function getServerVersion() : string { /** @var stdClass $serverInfo */ $serverInfo = db2_server_info($this->conn); @@ -68,7 +63,7 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return false; } @@ -76,11 +71,11 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($sql) + public function prepare(string $sql) : DriverStatement { $stmt = @db2_prepare($this->conn, $sql); if (! $stmt) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError(); } return new DB2Statement($stmt); @@ -89,10 +84,8 @@ public function prepare($sql) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); @@ -102,26 +95,20 @@ public function query() /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - $input = db2_escape_string($input); - - if ($type === ParameterType::INTEGER) { - return $input; - } - - return "'" . $input . "'"; + return "'" . db2_escape_string($input) . "'"; } /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = @db2_exec($this->conn, $statement); if ($stmt === false) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError(); } return db2_num_rows($stmt); @@ -130,7 +117,7 @@ public function exec($statement) /** * {@inheritdoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { return db2_last_insert_id($this->conn); } @@ -138,49 +125,38 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { - db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF); + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF)) { + throw DB2Exception::fromConnectionError($this->conn); + } } /** * {@inheritdoc} */ - public function commit() + public function commit() : void { if (! db2_commit($this->conn)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + throw DB2Exception::fromConnectionError($this->conn); } - db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); - } - /** - * {@inheritdoc} - */ - public function rollBack() - { - if (! db2_rollback($this->conn)) { - throw new DB2Exception(db2_conn_errormsg($this->conn)); + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { + throw DB2Exception::fromConnectionError($this->conn); } - db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); } /** * {@inheritdoc} */ - public function errorCode() + public function rollBack() : void { - return db2_conn_error($this->conn); - } + if (! db2_rollback($this->conn)) { + throw DB2Exception::fromConnectionError($this->conn); + } - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return [ - 0 => db2_conn_errormsg($this->conn), - 1 => $this->errorCode(), - ]; + if (! db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON)) { + throw DB2Exception::fromConnectionError($this->conn); + } } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php index fe79fe6bd37..604a46ad1e9 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php @@ -1,8 +1,15 @@ buildConnectionString($params, $username, $password); + + $username = $password = ''; } - return new DB2Connection($params, (string) $username, (string) $password, $driverOptions); + return new DB2Connection($params, $username, $password, $driverOptions); } /** - * {@inheritdoc} - * - * @deprecated + * @param string[] $params */ - public function getName() + private function buildConnectionString(array $params, string $username, string $password) : string { - return 'ibm_db2'; + $connectionParams = [ + 'DRIVER' => '{IBM DB2 ODBC DRIVER}', + 'DATABASE' => $params['dbname'], + 'HOSTNAME' => $params['host'], + 'PROTOCOL' => $params['protocol'] ?? 'TCPIP', + 'UID' => $username, + 'PWD' => $password, + ]; + + if (isset($params['port'])) { + $connectionParams['PORT'] = $params['port']; + } + + return implode(';', array_map(static function (string $key, string $value) : string { + return sprintf('%s=%s', $key, $value); + }, array_keys($connectionParams), $connectionParams)); } } diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php index b01c4552a23..bd8d5b298aa 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php @@ -1,9 +1,38 @@ bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { + assert(is_int($param)); + switch ($type) { case ParameterType::INTEGER: - $this->bind($column, $variable, DB2_PARAM_IN, DB2_LONG); + $this->bind($param, $variable, DB2_PARAM_IN, DB2_LONG); break; case ParameterType::LARGE_OBJECT: - if (isset($this->lobs[$column])) { - [, $handle] = $this->lobs[$column]; + if (isset($this->lobs[$param])) { + [, $handle] = $this->lobs[$param]; fclose($handle); } $handle = $this->createTemporaryFile(); $path = stream_get_meta_data($handle)['uri']; - $this->bind($column, $path, DB2_PARAM_FILE, DB2_BINARY); + $this->bind($param, $path, DB2_PARAM_FILE, DB2_BINARY); - $this->lobs[$column] = [&$variable, $handle]; + $this->lobs[$param] = [&$variable, $handle]; break; default: - $this->bind($column, $variable, DB2_PARAM_IN, DB2_CHAR); + $this->bind($param, $variable, DB2_PARAM_IN, DB2_CHAR); break; } - - return true; } /** @@ -132,35 +134,35 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l * * @throws DB2Exception */ - private function bind($position, &$variable, int $parameterType, int $dataType) : void + private function bind(int $position, &$variable, int $parameterType, int $dataType) : void { $this->bindParam[$position] =& $variable; if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError($this->stmt); } } /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { $this->bindParam = []; - if (! db2_free_result($this->stmt)) { - return false; + if (! $this->result) { + return; } - $this->result = false; + db2_free_result($this->stmt); - return true; + $this->result = false; } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return db2_num_fields($this->stmt) ?: 0; } @@ -168,26 +170,7 @@ public function columnCount() /** * {@inheritdoc} */ - public function errorCode() - { - return db2_stmt_error(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return [ - db2_stmt_errormsg(), - db2_stmt_error(), - ]; - } - - /** - * {@inheritdoc} - */ - public function execute($params = null) + public function execute(?array $params = null) : void { if ($params === null) { ksort($this->bindParam); @@ -218,24 +201,28 @@ public function execute($params = null) $this->lobs = []; if ($retval === false) { - throw new DB2Exception(db2_stmt_errormsg()); + throw DB2Exception::fromStatementError($this->stmt); } $this->result = true; - - return $retval; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; - return true; + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (! isset($args[1])) { + return; + } + + $this->defaultFetchClassCtorArgs = (array) $args[2]; } /** @@ -249,7 +236,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -272,10 +259,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (func_num_args() >= 2) { - $args = func_get_args(); - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } $result = db2_fetch_object($this->stmt); @@ -300,13 +286,13 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch(...func_get_args())) !== false) { + while (($row = $this->fetch($fetchMode, ...$args)) !== false) { $rows[] = $row; } break; @@ -327,7 +313,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); @@ -335,13 +321,17 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return @db2_num_rows($this->stmt) ? : 0; } @@ -353,11 +343,9 @@ public function rowCount() * @param string|object $destinationClass Name of the class or class instance to cast to. * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. * - * @return object - * * @throws DB2Exception */ - private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) + private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) : object { if (! is_string($destinationClass)) { if (! is_object($destinationClass)) { diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php b/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php index 1166e8d4c2e..882a16d030c 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php @@ -1,29 +1,28 @@ error, $connection->sqlstate ?: null, $connection->errno); + } +} diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php b/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php new file mode 100644 index 00000000000..24a83e34bfa --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Mysqli/Exception/FailedReadingStreamOffset.php @@ -0,0 +1,16 @@ +error, $statement->sqlstate ?: null, $statement->errno); + } +} diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownFetchMode.php b/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownFetchMode.php new file mode 100644 index 00000000000..42ed619d279 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Mysqli/Exception/UnknownFetchMode.php @@ -0,0 +1,19 @@ + $params + * @param array $driverOptions * * @throws MysqliException */ - public function __construct(array $params, $username, $password, array $driverOptions = []) + public function __construct(array $params, string $username, string $password, array $driverOptions = []) { - $port = $params['port'] ?? ini_get('mysqli.default_port'); + $port = $params['port'] ?? (int) ini_get('mysqli.default_port'); // Fallback to default MySQL port if not given. if (! $port) { @@ -55,20 +54,25 @@ public function __construct(array $params, $username, $password, array $driverOp } $socket = $params['unix_socket'] ?? ini_get('mysqli.default_socket'); - $dbname = $params['dbname'] ?? null; + $dbname = $params['dbname'] ?? ''; + $host = $params['host']; + + if (! empty($params['persistent'])) { + $host = 'p:' . $host; + } - $flags = $driverOptions[static::OPTION_FLAGS] ?? null; + $flags = $driverOptions[static::OPTION_FLAGS] ?? 0; $this->conn = mysqli_init(); $this->setSecureConnection($params); $this->setDriverOptions($driverOptions); - set_error_handler(static function () { + set_error_handler(static function () : void { }); try { - if (! $this->conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { - throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); + if (! $this->conn->real_connect($host, $username, $password, $dbname, $port, $socket, $flags)) { + throw ConnectionError::new($this->conn); } } finally { restore_error_handler(); @@ -85,10 +89,8 @@ public function __construct(array $params, $username, $password, array $driverOp * Retrieves mysqli native resource handle. * * Could be used if part of your application is not using DBAL. - * - * @return mysqli */ - public function getWrappedResourceHandle() + public function getWrappedResourceHandle() : mysqli { return $this->conn; } @@ -101,7 +103,7 @@ public function getWrappedResourceHandle() * * @link https://jira.mariadb.org/browse/MDEV-4088 */ - public function getServerVersion() + public function getServerVersion() : string { $serverInfos = $this->conn->get_server_info(); if (stripos($serverInfos, 'mariadb') !== false) { @@ -118,7 +120,7 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return false; } @@ -126,18 +128,16 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new MysqliStatement($this->conn, $prepareString); + return new MysqliStatement($this->conn, $sql); } /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); @@ -147,7 +147,7 @@ public function query() /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { return "'" . $this->conn->escape_string($input) . "'"; } @@ -155,10 +155,10 @@ public function quote($input, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { if ($this->conn->query($statement) === false) { - throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + throw ConnectionError::new($this->conn); } return $this->conn->affected_rows; @@ -167,62 +167,48 @@ public function exec($statement) /** * {@inheritdoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { - return $this->conn->insert_id; + return (string) $this->conn->insert_id; } /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->conn->query('START TRANSACTION'); - - return true; - } - - /** - * {@inheritdoc} - */ - public function commit() - { - return $this->conn->commit(); - } - - /** - * {@inheritdoc}non-PHPdoc) - */ - public function rollBack() - { - return $this->conn->rollback(); } /** * {@inheritdoc} */ - public function errorCode() + public function commit() : void { - return $this->conn->errno; + if (! $this->conn->commit()) { + throw ConnectionError::new($this->conn); + } } /** * {@inheritdoc} */ - public function errorInfo() + public function rollBack() : void { - return $this->conn->error; + if (! $this->conn->rollback()) { + throw ConnectionError::new($this->conn); + } } /** * Apply the driver options to the connection. * - * @param mixed[] $driverOptions + * @param array $driverOptions * * @throws MysqliException When one of of the options is not supported. * @throws MysqliException When applying doesn't work - e.g. due to incorrect value. */ - private function setDriverOptions(array $driverOptions = []) + private function setDriverOptions(array $driverOptions = []) : void { $supportedDriverOptions = [ MYSQLI_OPT_CONNECT_TIMEOUT, @@ -253,35 +239,30 @@ private function setDriverOptions(array $driverOptions = []) continue; } - $msg = sprintf($exceptionMsg, 'Failed to set', $option, $value); - $msg .= sprintf(', error: %s (%d)', mysqli_error($this->conn), mysqli_errno($this->conn)); - - throw new MysqliException( - $msg, - $this->conn->sqlstate, - $this->conn->errno - ); + throw ConnectionError::new($this->conn); } } /** * Pings the server and re-connects when `mysqli.reconnect = 1` * - * @return bool + * {@inheritDoc} */ - public function ping() + public function ping() : void { - return $this->conn->ping(); + if (! $this->conn->ping()) { + throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); + } } /** * Establish a secure connection * - * @param mixed[] $params + * @param array $params * * @throws MysqliException */ - private function setSecureConnection(array $params) + private function setSecureConnection(array $params) : void { if (! isset($params['ssl_key']) && ! isset($params['ssl_cert']) && diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php index 1fa0c900fbd..b779bc40457 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php @@ -1,5 +1,7 @@ _conn = $conn; - $stmt = $conn->prepare($prepareString); + $stmt = $conn->prepare($sql); if ($stmt === false) { - throw new MysqliException($this->_conn->error, $this->_conn->sqlstate, $this->_conn->errno); + throw ConnectionError::new($this->_conn); } $this->_stmt = $stmt; @@ -100,55 +106,49 @@ public function __construct(mysqli $conn, $prepareString) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { - assert(is_int($column)); + assert(is_int($param)); if (! isset(self::$_paramTypeMap[$type])) { - throw new MysqliException(sprintf("Unknown type: '%s'", $type)); + throw UnknownType::new($type); } - $this->_bindedValues[$column] =& $variable; - $this->types[$column - 1] = self::$_paramTypeMap[$type]; - - return true; + $this->_bindedValues[$param] =& $variable; + $this->types[$param - 1] = self::$_paramTypeMap[$type]; } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { assert(is_int($param)); if (! isset(self::$_paramTypeMap[$type])) { - throw new MysqliException(sprintf("Unknown type: '%s'", $type)); + throw UnknownType::new($type); } $this->_values[$param] = $value; $this->_bindedValues[$param] =& $this->_values[$param]; $this->types[$param - 1] = self::$_paramTypeMap[$type]; - - return true; } /** * {@inheritdoc} */ - public function execute($params = null) + public function execute(?array $params = null) : void { - if ($this->_bindedValues !== null) { - if ($params !== null) { - if (! $this->bindUntypedValues($params)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->errno); - } - } else { - $this->bindTypedParameters(); + if ($params !== null && count($params) > 0) { + if (! $this->bindUntypedValues($params)) { + throw StatementError::new($this->_stmt); } + } else { + $this->bindTypedParameters(); } if (! $this->_stmt->execute()) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw StatementError::new($this->_stmt); } if ($this->_columnNames === null) { @@ -195,19 +195,19 @@ public function execute($params = null) } if (! $this->_stmt->bind_result(...$refs)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw StatementError::new($this->_stmt); } } $this->result = true; - - return true; } /** * Binds parameters with known types previously bound to the statement + * + * @throws DriverException */ - private function bindTypedParameters() + private function bindTypedParameters() : void { $streams = $values = []; $types = $this->types; @@ -233,8 +233,8 @@ private function bindTypedParameters() $values[$parameter] = $value; } - if (! $this->_stmt->bind_param($types, ...$values)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + if (count($values) > 0 && ! $this->_stmt->bind_param($types, ...$values)) { + throw StatementError::new($this->_stmt); } $this->sendLongData($streams); @@ -243,20 +243,22 @@ private function bindTypedParameters() /** * Handle $this->_longData after regular query parameters have been bound * + * @param resource[] $streams + * * @throws MysqliException */ - private function sendLongData($streams) + private function sendLongData(array $streams) : void { foreach ($streams as $paramNr => $stream) { while (! feof($stream)) { $chunk = fread($stream, 8192); if ($chunk === false) { - throw new MysqliException("Failed reading the stream resource for parameter offset ${paramNr}."); + throw FailedReadingStreamOffset::new($paramNr); } if (! $this->_stmt->send_long_data($paramNr - 1, $chunk)) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw StatementError::new($this->_stmt); } } } @@ -266,10 +268,8 @@ private function sendLongData($streams) * Binds a array of values to bound parameters. * * @param mixed[] $values - * - * @return bool */ - private function bindUntypedValues(array $values) + private function bindUntypedValues(array $values) : bool { $params = []; $types = str_repeat('s', count($values)); @@ -303,7 +303,7 @@ private function _fetch() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -324,7 +324,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX } if ($values === false) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + throw StatementError::new($this->_stmt); } if ($fetchMode === FetchMode::NUMERIC) { @@ -346,14 +346,14 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX return (object) $assoc; default: - throw new MysqliException(sprintf("Unknown fetch type '%s'", $fetchMode)); + throw UnknownFetchMode::new($fetchMode); } } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; @@ -375,7 +375,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); @@ -383,40 +383,26 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; - } + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->_stmt->errno; + return $row[$columnIndex]; } /** * {@inheritdoc} */ - public function errorInfo() - { - return $this->_stmt->error; - } - - /** - * {@inheritdoc} - */ - public function closeCursor() + public function closeCursor() : void { $this->_stmt->free_result(); $this->result = false; - - return true; } /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { if ($this->_columnNames === false) { return $this->_stmt->affected_rows; @@ -428,7 +414,7 @@ public function rowCount() /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return $this->_stmt->field_count; } @@ -436,11 +422,9 @@ public function columnCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { $this->_defaultFetchMode = $fetchMode; - - return true; } /** diff --git a/lib/Doctrine/DBAL/Driver/OCI8/Driver.php b/lib/Doctrine/DBAL/Driver/OCI8/Driver.php index edda32d6a56..bf392885e70 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/Driver.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/Driver.php @@ -1,9 +1,12 @@ _constructDsn($params), $params['charset'] ?? '', $params['sessionMode'] ?? OCI_DEFAULT, @@ -37,18 +44,8 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - protected function _constructDsn(array $params) + protected function _constructDsn(array $params) : string { return $this->getEasyConnectString($params); } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'oci8'; - } } diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php index c1857936f5a..c2eac6d92a5 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -1,18 +1,18 @@ dbh); @@ -95,7 +88,7 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return false; } @@ -103,19 +96,16 @@ public function requiresQueryForServerVersion() /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new OCI8Statement($this->dbh, $prepareString, $this); + return new OCI8Statement($this->dbh, $sql, $this); } /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - $sql = $args[0]; - //$fetchMode = $args[1]; $stmt = $this->prepare($sql); $stmt->execute(); @@ -125,20 +115,15 @@ public function query() /** * {@inheritdoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($value) || is_float($value)) { - return $value; - } - $value = str_replace("'", "''", $value); - - return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + return "'" . addcslashes(str_replace("'", "''", $input), "\000\n\r\\\032") . "'"; } /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = $this->prepare($statement); $stmt->execute(); @@ -149,10 +134,10 @@ public function exec($statement) /** * {@inheritdoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { if ($name === null) { - return false; + throw new OCI8Exception('The driver does not support identity columns.'); } $sql = 'SELECT ' . $name . '.CURRVAL FROM DUAL'; @@ -163,15 +148,13 @@ public function lastInsertId($name = null) throw new OCI8Exception('lastInsertId failed: Query was executed but no result was returned.'); } - return (int) $result; + return $result; } /** * Returns the current execution mode. - * - * @return int */ - public function getExecuteMode() + public function getExecuteMode() : int { return $this->executeMode; } @@ -179,63 +162,32 @@ public function getExecuteMode() /** * {@inheritdoc} */ - public function beginTransaction() + public function beginTransaction() : void { $this->executeMode = OCI_NO_AUTO_COMMIT; - - return true; } /** * {@inheritdoc} */ - public function commit() + public function commit() : void { if (! oci_commit($this->dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } - $this->executeMode = OCI_COMMIT_ON_SUCCESS; - return true; - } - - /** - * {@inheritdoc} - */ - public function rollBack() - { - if (! oci_rollback($this->dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); - } $this->executeMode = OCI_COMMIT_ON_SUCCESS; - - return true; - } - - /** - * {@inheritdoc} - */ - public function errorCode() - { - $error = oci_error($this->dbh); - if ($error !== false) { - $error = $error['code']; - } - - return $error; } /** * {@inheritdoc} */ - public function errorInfo() + public function rollBack() : void { - $error = oci_error($this->dbh); - - if ($error === false) { - return []; + if (! oci_rollback($this->dbh)) { + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } - return $error; + $this->executeMode = OCI_COMMIT_ON_SUCCESS; } } diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php index af3a9d1a7a9..2e7f1693343 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php @@ -1,5 +1,7 @@ OCI_BOTH, @@ -97,7 +96,7 @@ class OCI8Statement implements IteratorAggregate, Statement * @param resource $dbh The connection handle. * @param string $query The SQL query. */ - public function __construct($dbh, $query, OCI8Connection $conn) + public function __construct($dbh, string $query, OCI8Connection $conn) { [$query, $paramMap] = self::convertPositionalToNamedPlaceholders($query); @@ -131,14 +130,14 @@ public function __construct($dbh, $query, OCI8Connection $conn) * @todo extract into utility class in Doctrine\DBAL\Util namespace * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements. */ - public static function convertPositionalToNamedPlaceholders($statement) + public static function convertPositionalToNamedPlaceholders(string $statement) : array { $fragmentOffset = $tokenOffset = 0; $fragments = $paramMap = []; $currentLiteralDelimiter = null; do { - if (! $currentLiteralDelimiter) { + if ($currentLiteralDelimiter === null) { $result = self::findPlaceholderOrOpeningQuote( $statement, $tokenOffset, @@ -154,7 +153,7 @@ public static function convertPositionalToNamedPlaceholders($statement) if ($currentLiteralDelimiter) { throw new OCI8Exception(sprintf( - 'The statement contains non-terminated string literal starting at offset %d', + 'The statement contains non-terminated string literal starting at offset %d.', $tokenOffset - 1 )); } @@ -168,24 +167,24 @@ public static function convertPositionalToNamedPlaceholders($statement) /** * Finds next placeholder or opening quote. * - * @param string $statement The SQL statement to parse - * @param string $tokenOffset The offset to start searching from - * @param int $fragmentOffset The offset to build the next fragment from - * @param string[] $fragments Fragments of the original statement not containing placeholders - * @param string|null $currentLiteralDelimiter The delimiter of the current string literal - * or NULL if not currently in a literal - * @param array $paramMap Mapping of the original parameter positions to their named replacements + * @param string $statement The SQL statement to parse + * @param int $tokenOffset The offset to start searching from + * @param int $fragmentOffset The offset to build the next fragment from + * @param string[] $fragments Fragments of the original statement not containing placeholders + * @param string|null $currentLiteralDelimiter The delimiter of the current string literal + * or NULL if not currently in a literal + * @param string[] $paramMap Mapping of the original parameter positions to their named replacements * * @return bool Whether the token was found */ private static function findPlaceholderOrOpeningQuote( - $statement, - &$tokenOffset, - &$fragmentOffset, - &$fragments, - &$currentLiteralDelimiter, - &$paramMap - ) { + string $statement, + int &$tokenOffset, + int &$fragmentOffset, + array &$fragments, + ?string &$currentLiteralDelimiter, + array &$paramMap + ) : bool { $token = self::findToken($statement, $tokenOffset, '/[?\'"]/'); if (! $token) { @@ -214,16 +213,16 @@ private static function findPlaceholderOrOpeningQuote( * Finds closing quote * * @param string $statement The SQL statement to parse - * @param string $tokenOffset The offset to start searching from + * @param int $tokenOffset The offset to start searching from * @param string $currentLiteralDelimiter The delimiter of the current string literal * * @return bool Whether the token was found */ private static function findClosingQuote( - $statement, - &$tokenOffset, - &$currentLiteralDelimiter - ) { + string $statement, + int &$tokenOffset, + string &$currentLiteralDelimiter + ) : bool { $token = self::findToken( $statement, $tokenOffset, @@ -234,7 +233,7 @@ private static function findClosingQuote( return false; } - $currentLiteralDelimiter = false; + $currentLiteralDelimiter = null; ++$tokenOffset; return true; @@ -250,7 +249,7 @@ private static function findClosingQuote( * * @return string|null Token or NULL if not found */ - private static function findToken($statement, &$offset, $regex) + private static function findToken(string $statement, int &$offset, string $regex) : ?string { if (preg_match($regex, $statement, $matches, PREG_OFFSET_CAPTURE, $offset)) { $offset = $matches[0][1]; @@ -264,17 +263,17 @@ private static function findToken($statement, &$offset, $regex) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type, null); + $this->bindParam($param, $value, $type, null); } /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { - $column = $this->_paramMap[$column]; + $param = $this->_paramMap[$param]; if ($type === ParameterType::LARGE_OBJECT) { $lob = oci_new_descriptor($this->_dbh, OCI_D_LOB); @@ -287,15 +286,17 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l $variable =& $lob; } - $this->boundValues[$column] =& $variable; + $this->boundValues[$param] =& $variable; - return oci_bind_by_name( + if (! oci_bind_by_name( $this->_sth, - $column, + $param, $variable, $length ?? -1, $this->convertParameterType($type) - ); + )) { + throw OCI8Exception::fromErrorInfo(oci_error($this->_sth)); + } } /** @@ -318,24 +319,22 @@ private function convertParameterType(int $type) : int /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { // not having the result means there's nothing to close if (! $this->result) { - return true; + return; } oci_cancel($this->_sth); $this->result = false; - - return true; } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return oci_num_fields($this->_sth) ?: 0; } @@ -343,65 +342,36 @@ public function columnCount() /** * {@inheritdoc} */ - public function errorCode() - { - $error = oci_error($this->_sth); - if ($error !== false) { - $error = $error['code']; - } - - return $error; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - $error = oci_error($this->_sth); - - if ($error === false) { - return []; - } - - return $error; - } - - /** - * {@inheritdoc} - */ - public function execute($params = null) + public function execute(?array $params = null) : void { if ($params) { $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { if ($hasZeroIndex && is_int($key)) { - $this->bindValue($key + 1, $val); + $param = $key + 1; } else { - $this->bindValue($key, $val); + $param = $key; } + + $this->bindValue($param, $val); } } $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode()); if (! $ret) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->_sth)); } $this->result = true; - - return $ret; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { $this->_defaultFetchMode = $fetchMode; - - return true; } /** @@ -415,7 +385,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -434,7 +404,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX } if (! isset(self::$fetchModeMap[$fetchMode])) { - throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); + throw new InvalidArgumentException(sprintf('Invalid fetch mode %d.', $fetchMode)); } return oci_fetch_array( @@ -446,7 +416,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; @@ -461,7 +431,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n } if (! isset(self::$fetchModeMap[$fetchMode])) { - throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); + throw new InvalidArgumentException(sprintf('Invalid fetch mode %d.', $fetchMode)); } if (self::$fetchModeMap[$fetchMode] === OCI_BOTH) { @@ -500,7 +470,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -514,13 +484,17 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return oci_num_rows($this->_sth) ?: 0; } diff --git a/lib/Doctrine/DBAL/Driver/PDOConnection.php b/lib/Doctrine/DBAL/Driver/PDOConnection.php index 336542ea50a..77704b77e81 100644 --- a/lib/Doctrine/DBAL/Driver/PDOConnection.php +++ b/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -1,32 +1,32 @@ $options * * @throws PDOException In case of an error. */ - public function __construct($dsn, $user = null, $password = null, ?array $options = null) + public function __construct(string $dsn, string $username = '', string $password = '', array $options = []) { try { - parent::__construct($dsn, (string) $user, (string) $password, (array) $options); - $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); - $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection = new PDO($dsn, $username, $password, $options); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -35,10 +35,10 @@ public function __construct($dsn, $user = null, $password = null, ?array $option /** * {@inheritdoc} */ - public function exec($statement) + public function exec(string $statement) : int { try { - return parent::exec($statement); + return $this->connection->exec($statement); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -47,18 +47,20 @@ public function exec($statement) /** * {@inheritdoc} */ - public function getServerVersion() + public function getServerVersion() : string { - return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); + return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION); } /** * {@inheritdoc} */ - public function prepare($prepareString, $driverOptions = []) + public function prepare(string $sql) : Statement { try { - return parent::prepare($prepareString, $driverOptions); + return $this->createStatement( + $this->connection->prepare($sql) + ); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -67,15 +69,13 @@ public function prepare($prepareString, $driverOptions = []) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - try { - $stmt = parent::query(...$args); + $stmt = $this->connection->query($sql); assert($stmt instanceof \PDOStatement); - return $stmt; + return $this->createStatement($stmt); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -84,22 +84,22 @@ public function query() /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - return parent::quote($input, $type); + return $this->connection->quote($input); } /** * {@inheritdoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { try { if ($name === null) { - return parent::lastInsertId(); + return $this->connection->lastInsertId(); } - return parent::lastInsertId($name); + return $this->connection->lastInsertId($name); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -108,8 +108,45 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return false; } + + /** + * Creates a wrapped statement + */ + protected function createStatement(\PDOStatement $stmt) : PDOStatement + { + return new PDOStatement($stmt); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() : void + { + $this->connection->beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() : void + { + $this->connection->commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() : void + { + $this->connection->rollBack(); + } + + public function getWrappedConnection() : PDO + { + return $this->connection; + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOException.php b/lib/Doctrine/DBAL/Driver/PDOException.php index 277d7a62500..e25fcd461ab 100644 --- a/lib/Doctrine/DBAL/Driver/PDOException.php +++ b/lib/Doctrine/DBAL/Driver/PDOException.php @@ -1,52 +1,26 @@ getMessage(), 0, $exception); - - $this->code = $exception->getCode(); - $this->errorInfo = $exception->errorInfo; - $this->errorCode = $exception->errorInfo[1] ?? $exception->getCode(); - $this->sqlState = $exception->errorInfo[0] ?? $exception->getCode(); - } + if ($exception->errorInfo !== null) { + [$sqlState, $code] = $exception->errorInfo; + } else { + $code = $exception->getCode(); + $sqlState = null; + } - /** - * {@inheritdoc} - */ - public function getErrorCode() - { - return $this->errorCode; - } - - /** - * {@inheritdoc} - */ - public function getSQLState() - { - return $this->sqlState; + parent::__construct($exception->getMessage(), $sqlState, $code, $exception); } } diff --git a/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php b/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php deleted file mode 100644 index 12fb14ef5cb..00000000000 --- a/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php +++ /dev/null @@ -1,59 +0,0 @@ -_constructPdoDsn($params), - $username, - $password, - $driverOptions - ); - } - - /** - * Constructs the IBM PDO DSN. - * - * @param mixed[] $params - * - * @return string The DSN. - */ - private function _constructPdoDsn(array $params) - { - $dsn = 'ibm:'; - if (isset($params['host'])) { - $dsn .= 'HOSTNAME=' . $params['host'] . ';'; - } - if (isset($params['port'])) { - $dsn .= 'PORT=' . $params['port'] . ';'; - } - $dsn .= 'PROTOCOL=TCPIP;'; - if (isset($params['dbname'])) { - $dsn .= 'DATABASE=' . $params['dbname'] . ';'; - } - - return $dsn; - } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_ibm'; - } -} diff --git a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php index dcd4ff51895..73ef818b143 100644 --- a/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php @@ -1,11 +1,15 @@ constructPdoDsn($params), @@ -38,7 +50,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - protected function constructPdoDsn(array $params) + protected function constructPdoDsn(array $params) : string { $dsn = 'mysql:'; if (isset($params['host']) && $params['host'] !== '') { @@ -59,14 +71,4 @@ protected function constructPdoDsn(array $params) return $dsn; } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_mysql'; - } } diff --git a/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php b/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php index f1239eafbd4..6dfcdb6b428 100644 --- a/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php @@ -1,11 +1,15 @@ constructPdoDsn($params), @@ -41,7 +53,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - private function constructPdoDsn(array $params) + private function constructPdoDsn(array $params) : string { $dsn = 'oci:dbname=' . $this->getEasyConnectString($params); @@ -51,12 +63,4 @@ private function constructPdoDsn(array $params) return $dsn; } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'pdo_oracle'; - } } diff --git a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php index f25cd5cded3..800be0adb19 100644 --- a/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -1,12 +1,15 @@ _constructPdoDsn($params), $username, $password, @@ -32,7 +43,7 @@ public function connect(array $params, $username = null, $password = null, array || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true ) ) { - $pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); + $connection->getWrappedConnection()->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); } /* defining client_encoding via SET NAMES to avoid inconsistent DSN support @@ -40,10 +51,10 @@ public function connect(array $params, $username = null, $password = null, array * - passing client_encoding via the 'options' param breaks pgbouncer support */ if (isset($params['charset'])) { - $pdo->exec('SET NAMES \'' . $params['charset'] . '\''); + $connection->exec('SET NAMES \'' . $params['charset'] . '\''); } - return $pdo; + return $connection; } catch (PDOException $e) { throw DBALException::driverException($this, $e); } @@ -56,7 +67,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - private function _constructPdoDsn(array $params) + private function _constructPdoDsn(array $params) : string { $dsn = 'pgsql:'; @@ -105,14 +116,4 @@ private function _constructPdoDsn(array $params) return $dsn; } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_pgsql'; - } } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php index d08c6a2c848..89598f0826c 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -1,12 +1,15 @@ _userDefinedFunctions = array_merge( $this->_userDefinedFunctions, @@ -35,7 +42,7 @@ public function connect(array $params, $username = null, $password = null, array } try { - $pdo = new PDOConnection( + $connection = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, @@ -45,11 +52,13 @@ public function connect(array $params, $username = null, $password = null, array throw DBALException::driverException($this, $ex); } + $pdo = $connection->getWrappedConnection(); + foreach ($this->_userDefinedFunctions as $fn => $data) { $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); } - return $pdo; + return $connection; } /** @@ -59,7 +68,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - protected function _constructPdoDsn(array $params) + protected function _constructPdoDsn(array $params) : string { $dsn = 'sqlite:'; if (isset($params['path'])) { @@ -70,14 +79,4 @@ protected function _constructPdoDsn(array $params) return $dsn; } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_sqlite'; - } } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php index bd3894477b5..ae8c43b9d9b 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -1,10 +1,11 @@ setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]); - } - /** * {@inheritDoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { if ($name === null) { return parent::lastInsertId($name); @@ -40,9 +32,9 @@ public function lastInsertId($name = null) /** * {@inheritDoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - $val = parent::quote($value, $type); + $val = parent::quote($input); // Fix for a driver version terminating all values with null byte if (strpos($val, "\0") !== false) { @@ -51,4 +43,12 @@ public function quote($value, $type = ParameterType::STRING) return $val; } + + /** + * {@inheritDoc} + */ + protected function createStatement(\PDOStatement $stmt) : PDOStatement + { + return new Statement($stmt); + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php index 6d6c4844d57..4096d5127b6 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -1,8 +1,12 @@ $value) { @@ -26,6 +34,10 @@ public function connect(array $params, $username = null, $password = null, array } } + if (! empty($params['persistent'])) { + $pdoOptions[PDO::ATTR_PERSISTENT] = true; + } + return new Connection( $this->_constructPdoDsn($params, $dsnOptions), $username, @@ -42,7 +54,7 @@ public function connect(array $params, $username = null, $password = null, array * * @return string The DSN. */ - private function _constructPdoDsn(array $params, array $connectionOptions) + private function _constructPdoDsn(array $params, array $connectionOptions) : string { $dsn = 'sqlsrv:server='; @@ -80,14 +92,4 @@ private function getConnectionOptionsDsn(array $connectionOptions) : string return $connectionOptionsDsn; } - - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'pdo_sqlsrv'; - } } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php index 6803bb14ed7..ba5d3dc87d8 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php @@ -1,5 +1,7 @@ bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } } diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 5be4f2c046d..85b47690c3e 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -1,13 +1,18 @@ PDO::PARAM_NULL, @@ -37,34 +42,23 @@ class PDOStatement extends \PDOStatement implements Statement FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, ]; - /** - * Protected constructor. - */ - protected function __construct() + /** @var \PDOStatement */ + private $stmt; + + public function __construct(\PDOStatement $stmt) { + $this->stmt = $stmt; } /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { $fetchMode = $this->convertFetchMode($fetchMode); - // This thin wrapper is necessary to shield against the weird signature - // of PDOStatement::setFetchMode(): even if the second and third - // parameters are optional, PHP will not let us remove it from this - // declaration. try { - if ($arg2 === null && $arg3 === null) { - return parent::setFetchMode($fetchMode); - } - - if ($arg3 === null) { - return parent::setFetchMode($fetchMode, $arg2); - } - - return parent::setFetchMode($fetchMode, $arg2, $arg3); + $this->stmt->setFetchMode($fetchMode, ...$args); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -73,12 +67,12 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { $type = $this->convertParamType($type); try { - return parent::bindValue($param, $value, $type); + $this->stmt->bindValue($param, $value, $type); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -87,12 +81,17 @@ public function bindValue($param, $value, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null) : void { - $type = $this->convertParamType($type); + $type = $this->convertParamType($type); + $extraParameters = array_slice(func_get_args(), 3); + + if (count($extraParameters) !== 0) { + $extraParameters[0] = $extraParameters[0] ?? 0; + } try { - return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); + $this->stmt->bindParam($param, $variable, $type, ...$extraParameters); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -101,24 +100,26 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { - try { - return parent::closeCursor(); - } catch (\PDOException $exception) { - // Exceptions not allowed by the interface. - // In case driver implementations do not adhere to the interface, silence exceptions here. - return true; - } + $this->stmt->closeCursor(); + } + + /** + * {@inheritdoc} + */ + public function columnCount() : int + { + return $this->stmt->columnCount(); } /** * {@inheritdoc} */ - public function execute($params = null) + public function execute(?array $params = null) : void { try { - return parent::execute($params); + $this->stmt->execute($params); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -127,16 +128,24 @@ public function execute($params = null) /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function rowCount() : int { - $args = func_get_args(); - - if (isset($args[0])) { - $args[0] = $this->convertFetchMode($args[0]); - } + return $this->stmt->rowCount(); + } + /** + * {@inheritdoc} + */ + public function fetch(?int $fetchMode = null, ...$args) + { try { - return parent::fetch(...$args); + if ($fetchMode === null) { + return $this->stmt->fetch(); + } + + $fetchMode = $this->convertFetchMode($fetchMode); + + return $this->stmt->fetch($fetchMode, ...$args); } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -145,41 +154,43 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { - $args = func_get_args(); - - if (isset($args[0])) { - $args[0] = $this->convertFetchMode($args[0]); - } - - if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) { - $args = []; - } elseif ($fetchArgument === null && $ctorArgs === null) { - $args = [$fetchMode]; - } elseif ($ctorArgs === null) { - $args = [$fetchMode, $fetchArgument]; - } else { - $args = [$fetchMode, $fetchArgument, $ctorArgs]; - } - try { - $data = parent::fetchAll(...$args); - assert(is_array($data)); - - return $data; + if ($fetchMode === null) { + $data = $this->stmt->fetchAll(); + } else { + $data = $this->stmt->fetchAll( + $this->convertFetchMode($fetchMode), + ...$args + ); + } } catch (\PDOException $exception) { throw new PDOException($exception); } + + assert(is_array($data)); + + return $data; } /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { try { - return parent::fetchColumn($columnIndex); + $value = $this->stmt->fetchColumn($columnIndex); + + if ($value === null) { + $columnCount = $this->columnCount(); + + if ($columnIndex < 0 || $columnIndex >= $columnCount) { + throw InvalidColumnIndex::new($columnIndex, $columnCount); + } + } + + return $value; } catch (\PDOException $exception) { throw new PDOException($exception); } @@ -195,7 +206,7 @@ private function convertParamType(int $type) : int if (! isset(self::PARAM_TYPE_MAP[$type])) { // TODO: next major: throw an exception @trigger_error(sprintf( - 'Using a PDO parameter type (%d given) is deprecated and will cause an error in Doctrine 3.0', + 'Using a PDO parameter type (%d given) is deprecated and will cause an error in Doctrine 3.0.', $type ), E_USER_DEPRECATED); @@ -216,7 +227,7 @@ private function convertFetchMode(int $fetchMode) : int // TODO: next major: throw an exception @trigger_error(sprintf( 'Using a PDO fetch mode or their combination (%d given)' . - ' is deprecated and will cause an error in Doctrine 3.0', + ' is deprecated and will cause an error in Doctrine 3.0.', $fetchMode ), E_USER_DEPRECATED); @@ -225,4 +236,12 @@ private function convertFetchMode(int $fetchMode) : int return self::FETCH_MODE_MAP[$fetchMode]; } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + yield from $this->stmt; + } } diff --git a/lib/Doctrine/DBAL/Driver/PingableConnection.php b/lib/Doctrine/DBAL/Driver/PingableConnection.php index 06bfb9a7f26..9a823dc83e8 100644 --- a/lib/Doctrine/DBAL/Driver/PingableConnection.php +++ b/lib/Doctrine/DBAL/Driver/PingableConnection.php @@ -1,5 +1,7 @@ buildDsn( - $params['host'] ?? null, - $params['port'] ?? null, - $params['server'] ?? null, - $params['dbname'] ?? null, - $username, - $password, - $driverOptions - ), + $this->buildDsn($params, $username, $password, $driverOptions), $params['persistent'] ?? false ); } catch (SQLAnywhereException $e) { @@ -38,50 +39,43 @@ public function connect(array $params, $username = null, $password = null, array } } - /** - * {@inheritdoc} - * - * @deprecated - */ - public function getName() - { - return 'sqlanywhere'; - } - /** * Build the connection string for given connection parameters and driver options. * - * @param string $host Host address to connect to. - * @param int $port Port to use for the connection (default to SQL Anywhere standard port 2638). - * @param string $server Database server name on the host to connect to. - * SQL Anywhere allows multiple database server instances on the same host, - * therefore specifying the server instance name to use is mandatory. - * @param string $dbname Name of the database on the server instance to connect to. + * @param mixed[] $params DBAL connection parameters * @param string $username User name to use for connection authentication. * @param string $password Password to use for connection authentication. * @param mixed[] $driverOptions Additional parameters to use for the connection. - * - * @return string */ - private function buildDsn($host, $port, $server, $dbname, $username = null, $password = null, array $driverOptions = []) + private function buildDsn(array $params, string $username, string $password, array $driverOptions = []) : string { - $host = $host ?: 'localhost'; - $port = $port ?: 2638; + $connectionParams = []; - if (! empty($server)) { - $server = ';ServerName=' . $server; + if (isset($params['host'])) { + $host = $params['host']; + + if (isset($params['port'])) { + $host .= sprintf(':%d', $params['port']); + } + + $connectionParams['HOST'] = $host; } - return 'HOST=' . $host . ':' . $port . - $server . - ';DBN=' . $dbname . - ';UID=' . $username . - ';PWD=' . $password . - ';' . implode( - ';', - array_map(static function ($key, $value) { - return $key . '=' . $value; - }, array_keys($driverOptions), $driverOptions) - ); + if (isset($params['server'])) { + $connectionParams['ServerName'] = $params['server']; + } + + if (isset($params['dbname'])) { + $connectionParams['DBN'] = $params['dbname']; + } + + $connectionParams['UID'] = $username; + $connectionParams['PWD'] = $password; + + $connectionParams = array_merge($connectionParams, $driverOptions); + + return implode(';', array_map(static function (string $key, string $value) : string { + return sprintf('%s=%s', $key, $value); + }, array_keys($connectionParams), $connectionParams)); } } diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index d47782003e6..e815f760bda 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -1,21 +1,19 @@ connection = $persistent ? @sasql_pconnect($dsn) : @sasql_connect($dsn); @@ -63,13 +61,11 @@ public function __construct($dsn, $persistent = false) * * @throws SQLAnywhereException */ - public function beginTransaction() + public function beginTransaction() : void { if (! sasql_set_option($this->connection, 'auto_commit', 'off')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } - - return true; } /** @@ -77,37 +73,19 @@ public function beginTransaction() * * @throws SQLAnywhereException */ - public function commit() + public function commit() : void { if (! sasql_commit($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); - - return true; } /** * {@inheritdoc} */ - public function errorCode() - { - return sasql_errorcode($this->connection); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return sasql_error($this->connection); - } - - /** - * {@inheritdoc} - */ - public function exec($statement) + public function exec(string $statement) : int { if (sasql_real_query($this->connection, $statement) === false) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); @@ -119,7 +97,7 @@ public function exec($statement) /** * {@inheritdoc} */ - public function getServerVersion() + public function getServerVersion() : string { $version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchColumn(); @@ -131,7 +109,7 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { if ($name === null) { return sasql_insert_id($this->connection); @@ -143,19 +121,17 @@ public function lastInsertId($name = null) /** * {@inheritdoc} */ - public function prepare($prepareString) + public function prepare(string $sql) : DriverStatement { - return new SQLAnywhereStatement($this->connection, $prepareString); + return new SQLAnywhereStatement($this->connection, $sql); } /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - $stmt = $this->prepare($args[0]); - + $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; @@ -164,19 +140,15 @@ public function query() /** * {@inheritdoc} */ - public function quote($input, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($input) || is_float($input)) { - return $input; - } - return "'" . sasql_escape_string($this->connection, $input) . "'"; } /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return true; } @@ -186,30 +158,24 @@ public function requiresQueryForServerVersion() * * @throws SQLAnywhereException */ - public function rollBack() + public function rollBack() : void { if (! sasql_rollback($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); - - return true; } /** * Ends transactional mode and enables auto commit again. * - * @return bool Whether or not ending transactional mode succeeded. - * * @throws SQLAnywhereException */ - private function endTransaction() + private function endTransaction() : void { if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } - - return true; } } diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php index 0f8bc3e57e6..5613acf9960 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php @@ -1,9 +1,10 @@ __invoke($conn) + )); } $this->conn = $conn; @@ -89,8 +93,10 @@ public function __construct($conn, $sql) * * @throws SQLAnywhereException */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { + assert(is_int($param)); + switch ($type) { case ParameterType::INTEGER: case ParameterType::BOOLEAN: @@ -108,70 +114,46 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l break; default: - throw new SQLAnywhereException('Unknown type: ' . $type); + throw new SQLAnywhereException(sprintf('Unknown type %d.', $type)); } - $this->boundValues[$column] =& $variable; + $this->boundValues[$param] =& $variable; - if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) { + if (! sasql_stmt_bind_param_ex($this->stmt, $param - 1, $variable, $type, $variable === null)) { throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); } - - return true; } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { - return $this->bindParam($param, $value, $type); + $this->bindParam($param, $value, $type); } /** * {@inheritdoc} - * - * @throws SQLAnywhereException */ - public function closeCursor() + public function closeCursor() : void { - if (! sasql_stmt_reset($this->stmt)) { - throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); - } - - return true; + sasql_stmt_reset($this->stmt); } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return sasql_stmt_field_count($this->stmt); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return sasql_stmt_errno($this->stmt); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return sasql_stmt_error($this->stmt); - } - /** * {@inheritdoc} * * @throws SQLAnywhereException */ - public function execute($params = null) + public function execute(?array $params = null) : void { if (is_array($params)) { $hasZeroIndex = array_key_exists(0, $params); @@ -190,8 +172,6 @@ public function execute($params = null) } $this->result = sasql_stmt_result_metadata($this->stmt); - - return true; } /** @@ -199,7 +179,7 @@ public function execute($params = null) * * @throws SQLAnywhereException */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { if (! is_resource($this->result)) { return false; @@ -221,10 +201,9 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (func_num_args() >= 2) { - $args = func_get_args(); - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } $result = sasql_fetch_object($this->result); @@ -242,14 +221,14 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX return sasql_fetch_object($this->result); default: - throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode); + throw new SQLAnywhereException(sprintf('Fetch mode is not supported %d.', $fetchMode)); } } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $rows = []; @@ -278,7 +257,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); @@ -286,7 +265,11 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** @@ -300,7 +283,7 @@ public function getIterator() /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { return sasql_stmt_affected_rows($this->stmt); } @@ -308,11 +291,19 @@ public function rowCount() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; + + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (! isset($args[1])) { + return; + } + + $this->defaultFetchClassCtorArgs = (array) $args[1]; } /** @@ -322,17 +313,15 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) * @param string|object $destinationClass Name of the class or class instance to cast to. * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. * - * @return object - * * @throws SQLAnywhereException */ - private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) + private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) : object { if (! is_string($destinationClass)) { if (! is_object($destinationClass)) { throw new SQLAnywhereException(sprintf( - 'Destination class has to be of type string or object, %s given.', - gettype($destinationClass) + 'Destination class has to be of type string or object, "%s" given.', + (new GetVariableType())->__invoke($destinationClass) )); } } else { diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php b/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php index 848ab5eef91..c786b996c58 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php @@ -1,8 +1,11 @@ id = $id; } - /** - * @return int - */ - public function getId() + public function getId() : ?string { return $this->id; } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index 35ad913ff5b..a6b09b02818 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -1,20 +1,17 @@ $connectionOptions * * @throws SQLSrvException */ - public function __construct($serverName, $connectionOptions) + public function __construct(string $serverName, array $connectionOptions) { if (! sqlsrv_configure('WarningsReturnAsErrors', 0)) { throw SQLSrvException::fromSqlSrvErrors(); @@ -57,7 +53,7 @@ public function __construct($serverName, $connectionOptions) /** * {@inheritdoc} */ - public function getServerVersion() + public function getServerVersion() : string { $serverInfo = sqlsrv_server_info($this->conn); @@ -67,7 +63,7 @@ public function getServerVersion() /** * {@inheritdoc} */ - public function requiresQueryForServerVersion() + public function requiresQueryForServerVersion() : bool { return false; } @@ -75,7 +71,7 @@ public function requiresQueryForServerVersion() /** * {@inheritDoc} */ - public function prepare($sql) + public function prepare(string $sql) : DriverStatement { return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId); } @@ -83,10 +79,8 @@ public function prepare($sql) /** * {@inheritDoc} */ - public function query() + public function query(string $sql) : ResultStatement { - $args = func_get_args(); - $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); @@ -96,23 +90,15 @@ public function query() /** * {@inheritDoc} */ - public function quote($value, $type = ParameterType::STRING) + public function quote(string $input) : string { - if (is_int($value)) { - return $value; - } - - if (is_float($value)) { - return sprintf('%F', $value); - } - - return "'" . str_replace("'", "''", $value) . "'"; + return "'" . str_replace("'", "''", $input) . "'"; } /** * {@inheritDoc} */ - public function exec($statement) + public function exec(string $statement) : int { $stmt = sqlsrv_query($this->conn, $statement); @@ -132,7 +118,7 @@ public function exec($statement) /** * {@inheritDoc} */ - public function lastInsertId($name = null) + public function lastInsertId(?string $name = null) : string { if ($name !== null) { $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); @@ -147,7 +133,7 @@ public function lastInsertId($name = null) /** * {@inheritDoc} */ - public function beginTransaction() + public function beginTransaction() : void { if (! sqlsrv_begin_transaction($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); @@ -157,7 +143,7 @@ public function beginTransaction() /** * {@inheritDoc} */ - public function commit() + public function commit() : void { if (! sqlsrv_commit($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); @@ -167,31 +153,10 @@ public function commit() /** * {@inheritDoc} */ - public function rollBack() + public function rollBack() : void { if (! sqlsrv_rollback($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); } } - - /** - * {@inheritDoc} - */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php index 1c1e8c472d7..87e982c9d82 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php @@ -1,5 +1,7 @@ conn = $conn; $this->sql = $sql; @@ -148,13 +146,9 @@ public function __construct($conn, $sql, ?LastInsertId $lastInsertId = null) /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { - if (! is_numeric($param)) { - throw new SQLSrvException( - 'sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.' - ); - } + assert(is_int($param)); $this->variables[$param] = $value; $this->types[$param] = $type; @@ -163,14 +157,12 @@ public function bindValue($param, $value, $type = ParameterType::STRING) /** * {@inheritdoc} */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { - if (! is_numeric($column)) { - throw new SQLSrvException('sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.'); - } + assert(is_int($param)); - $this->variables[$column] =& $variable; - $this->types[$column] = $type; + $this->variables[$param] =& $variable; + $this->types[$param] = $type; // unset the statement resource if it exists as the new one will need to be bound to the new variable $this->stmt = null; @@ -179,29 +171,27 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { // not having the result means there's nothing to close if ($this->stmt === null || ! $this->result) { - return true; + return; } // emulate it by fetching and discarding rows, similarly to what PDO does in this case // @link http://php.net/manual/en/pdostatement.closecursor.php // @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075 // deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them - while (sqlsrv_fetch($this->stmt)) { + while (sqlsrv_fetch($this->stmt) !== false) { } $this->result = false; - - return true; } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { if ($this->stmt === null) { return 0; @@ -213,28 +203,7 @@ public function columnCount() /** * {@inheritdoc} */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } - - /** - * {@inheritdoc} - */ - public function execute($params = null) + public function execute(?array $params = null) : void { if ($params) { $hasZeroIndex = array_key_exists(0, $params); @@ -313,13 +282,19 @@ private function prepare() /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { - $this->defaultFetchMode = $fetchMode; - $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; - $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; + $this->defaultFetchMode = $fetchMode; - return true; + if (isset($args[0])) { + $this->defaultFetchClass = $args[0]; + } + + if (! isset($args[1])) { + return; + } + + $this->defaultFetchClassCtorArgs = (array) $args[1]; } /** @@ -335,7 +310,7 @@ public function getIterator() * * @throws SQLSrvException */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation @@ -343,7 +318,6 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX return false; } - $args = func_get_args(); $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchMode === FetchMode::COLUMN) { @@ -358,27 +332,27 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; - if (count($args) >= 2) { - $className = $args[1]; - $ctorArgs = $args[2] ?? []; + if (count($args) > 0) { + $className = $args[0]; + $ctorArgs = $args[1] ?? []; } return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false; } - throw new SQLSrvException('Fetch mode is not supported!'); + throw new SQLSrvException('Fetch mode is not supported.'); } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch(...func_get_args())) !== false) { + while (($row = $this->fetch($fetchMode, ...$args)) !== false) { $rows[] = $row; } break; @@ -401,7 +375,7 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); @@ -409,13 +383,17 @@ public function fetchColumn($columnIndex = 0) return false; } - return $row[$columnIndex] ?? null; + if (! array_key_exists($columnIndex, $row)) { + throw InvalidColumnIndex::new($columnIndex, count($row)); + } + + return $row[$columnIndex]; } /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { if ($this->stmt === null) { return 0; diff --git a/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php b/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php index c97a60fa356..e667dddaf92 100644 --- a/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php +++ b/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php @@ -1,5 +1,7 @@ PDOMySQLDriver::class, - 'pdo_sqlite' => PDOSQLiteDriver::class, - 'pdo_pgsql' => PDOPgSQLDriver::class, - 'pdo_oci' => PDOOCIDriver::class, - 'oci8' => OCI8Driver::class, - 'ibm_db2' => DB2Driver::class, - 'pdo_sqlsrv' => PDOSQLSrvDriver::class, - 'mysqli' => MySQLiDriver::class, - 'drizzle_pdo_mysql' => DrizzlePDOMySQLDriver::class, - 'sqlanywhere' => SQLAnywhereDriver::class, - 'sqlsrv' => SQLSrvDriver::class, + 'pdo_mysql' => PDOMySQLDriver::class, + 'pdo_sqlite' => PDOSQLiteDriver::class, + 'pdo_pgsql' => PDOPgSQLDriver::class, + 'pdo_oci' => PDOOCIDriver::class, + 'oci8' => OCI8Driver::class, + 'ibm_db2' => DB2Driver::class, + 'pdo_sqlsrv' => PDOSQLSrvDriver::class, + 'mysqli' => MySQLiDriver::class, + 'sqlanywhere' => SQLAnywhereDriver::class, + 'sqlsrv' => SQLSrvDriver::class, ]; /** @@ -100,7 +103,6 @@ private function __construct() * sqlanywhere * sqlsrv * ibm_db2 (unstable) - * drizzle_pdo_mysql * * OR 'driverClass' that contains the full class name (with namespace) of the * driver class to instantiate. @@ -171,17 +173,7 @@ public static function getConnection( } } - // check for existing pdo object - if (isset($params['pdo']) && ! $params['pdo'] instanceof PDO) { - throw DBALException::invalidPdoInstance(); - } - - if (isset($params['pdo'])) { - $params['pdo']->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(PDO::ATTR_DRIVER_NAME); - } else { - self::_checkParams($params); - } + self::_checkParams($params); $className = $params['driverClass'] ?? self::$_driverMap[$params['driver']]; @@ -190,7 +182,7 @@ public static function getConnection( $wrapperClass = Connection::class; if (isset($params['wrapperClass'])) { if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) { - throw DBALException::invalidWrapperClass($params['wrapperClass']); + throw InvalidWrapperClass::new($params['wrapperClass']); } $wrapperClass = $params['wrapperClass']; @@ -222,18 +214,18 @@ private static function _checkParams(array $params) : void // driver if (! isset($params['driver']) && ! isset($params['driverClass'])) { - throw DBALException::driverRequired(); + throw DriverRequired::new(); } // check validity of parameters // driver if (isset($params['driver']) && ! isset(self::$_driverMap[$params['driver']])) { - throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap)); + throw UnknownDriver::new($params['driver'], array_keys(self::$_driverMap)); } if (isset($params['driverClass']) && ! in_array(Driver::class, class_implements($params['driverClass'], true))) { - throw DBALException::invalidDriverClass($params['driverClass']); + throw InvalidDriverClass::new($params['driverClass']); } } @@ -277,10 +269,6 @@ private static function parseDatabaseUrl(array $params) : array $url = array_map('rawurldecode', $url); - // If we have a connection URL, we have to unset the default PDO instance connection parameter (if any) - // as we cannot merge connection details from the URL into the PDO instance (URL takes precedence). - unset($params['pdo']); - $params = self::parseDatabaseUrlScheme($url, $params); if (isset($url['host'])) { @@ -434,7 +422,7 @@ private static function parseDatabaseUrlScheme(array $url, array $params) : arra // If a schemeless connection URL is given, we require a default driver or default custom driver // as connection parameter. if (! isset($params['driverClass']) && ! isset($params['driver'])) { - throw DBALException::driverRequired($params['url']); + throw DriverRequired::new($params['url']); } return $params; diff --git a/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php b/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php index bb0ca886d99..38d0b26f537 100644 --- a/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php +++ b/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php @@ -1,12 +1,11 @@ connection = $connection; } - /** - * @return Connection - */ - public function getConnection() + public function getConnection() : Connection { return $this->connection; } - - /** - * @return Driver - */ - public function getDriver() - { - return $this->connection->getDriver(); - } - - /** - * @return AbstractPlatform - */ - public function getDatabasePlatform() - { - return $this->connection->getDatabasePlatform(); - } - - /** - * @return AbstractSchemaManager - */ - public function getSchemaManager() - { - return $this->connection->getSchemaManager(); - } } diff --git a/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php b/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php deleted file mode 100644 index 9e722904050..00000000000 --- a/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php +++ /dev/null @@ -1,58 +0,0 @@ -charset = $charset; - $this->collation = $collation; - } - - /** - * @return void - */ - public function postConnect(ConnectionEventArgs $args) - { - $collation = $this->collation ? ' COLLATE ' . $this->collation : ''; - $args->getConnection()->executeUpdate('SET NAMES ' . $this->charset . $collation); - } - - /** - * {@inheritdoc} - */ - public function getSubscribedEvents() - { - return [Events::postConnect]; - } -} diff --git a/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php b/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php index 19f2b3fd335..fcd2e01f977 100644 --- a/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php +++ b/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php @@ -1,5 +1,7 @@ */ protected $_defaultSessionVars = [ 'NLS_TIME_FORMAT' => 'HH24:MI:SS', 'NLS_DATE_FORMAT' => 'YYYY-MM-DD HH24:MI:SS', @@ -33,17 +35,14 @@ class OracleSessionInit implements EventSubscriber ]; /** - * @param string[] $oracleSessionVars + * @param array $oracleSessionVars */ public function __construct(array $oracleSessionVars = []) { $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars); } - /** - * @return void - */ - public function postConnect(ConnectionEventArgs $args) + public function postConnect(ConnectionEventArgs $args) : void { if (! count($this->_defaultSessionVars)) { return; @@ -65,7 +64,7 @@ public function postConnect(ConnectionEventArgs $args) /** * {@inheritdoc} */ - public function getSubscribedEvents() + public function getSubscribedEvents() : array { return [Events::postConnect]; } diff --git a/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php b/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php index ea63cab43d7..e1eee9840ef 100644 --- a/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php +++ b/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php @@ -1,5 +1,7 @@ sql = $sql; } - /** - * @return void - */ - public function postConnect(ConnectionEventArgs $args) + public function postConnect(ConnectionEventArgs $args) : void { $conn = $args->getConnection(); $conn->exec($this->sql); @@ -34,7 +30,7 @@ public function postConnect(ConnectionEventArgs $args) /** * {@inheritdoc} */ - public function getSubscribedEvents() + public function getSubscribedEvents() : array { return [Events::postConnect]; } diff --git a/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php index 2f9edfea688..8d12d74cc48 100644 --- a/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php @@ -1,12 +1,13 @@ */ private $sql = []; public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatform $platform) @@ -32,50 +33,35 @@ public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatfo $this->platform = $platform; } - /** - * @return Column - */ - public function getColumn() + public function getColumn() : Column { return $this->column; } - /** - * @return TableDiff - */ - public function getTableDiff() + public function getTableDiff() : TableDiff { return $this->tableDiff; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php index 55661d5d307..cc3019d4faf 100644 --- a/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php @@ -1,12 +1,13 @@ */ private $sql = []; public function __construct(ColumnDiff $columnDiff, TableDiff $tableDiff, AbstractPlatform $platform) @@ -32,50 +33,35 @@ public function __construct(ColumnDiff $columnDiff, TableDiff $tableDiff, Abstra $this->platform = $platform; } - /** - * @return ColumnDiff - */ - public function getColumnDiff() + public function getColumnDiff() : ColumnDiff { return $this->columnDiff; } - /** - * @return TableDiff - */ - public function getTableDiff() + public function getTableDiff() : TableDiff { return $this->tableDiff; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php index 8f5f0ecf563..910b4827232 100644 --- a/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php @@ -1,11 +1,12 @@ */ private $sql = []; public function __construct(TableDiff $tableDiff, AbstractPlatform $platform) @@ -27,42 +28,30 @@ public function __construct(TableDiff $tableDiff, AbstractPlatform $platform) $this->platform = $platform; } - /** - * @return TableDiff - */ - public function getTableDiff() + public function getTableDiff() : TableDiff { return $this->tableDiff; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaAlterTableEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php index 1bc9f590187..06dd5641b74 100644 --- a/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php @@ -1,12 +1,13 @@ */ private $sql = []; public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatform $platform) @@ -32,50 +33,35 @@ public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatfo $this->platform = $platform; } - /** - * @return Column - */ - public function getColumn() + public function getColumn() : Column { return $this->column; } - /** - * @return TableDiff - */ - public function getTableDiff() + public function getTableDiff() : TableDiff { return $this->tableDiff; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php index 911ea8b4ab6..8f9059b119a 100644 --- a/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php @@ -1,12 +1,13 @@ */ private $sql = []; - /** - * @param string $oldColumnName - */ - public function __construct($oldColumnName, Column $column, TableDiff $tableDiff, AbstractPlatform $platform) + public function __construct(string $oldColumnName, Column $column, TableDiff $tableDiff, AbstractPlatform $platform) { $this->oldColumnName = $oldColumnName; $this->column = $column; @@ -39,58 +37,40 @@ public function __construct($oldColumnName, Column $column, TableDiff $tableDiff $this->platform = $platform; } - /** - * @return string - */ - public function getOldColumnName() + public function getOldColumnName() : string { return $this->oldColumnName; } - /** - * @return Column - */ - public function getColumn() + public function getColumn() : Column { return $this->column; } - /** - * @return TableDiff - */ - public function getTableDiff() + public function getTableDiff() : TableDiff { return $this->tableDiff; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php index 19d9f93a329..36041797458 100644 --- a/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php @@ -1,9 +1,10 @@ */ private $tableColumn; @@ -31,11 +32,9 @@ class SchemaColumnDefinitionEventArgs extends SchemaEventArgs private $connection; /** - * @param mixed[] $tableColumn - * @param string $table - * @param string $database + * @param array $tableColumn */ - public function __construct(array $tableColumn, $table, $database, Connection $connection) + public function __construct(array $tableColumn, string $table, string $database, Connection $connection) { $this->tableColumn = $tableColumn; $this->table = $table; @@ -47,60 +46,40 @@ public function __construct(array $tableColumn, $table, $database, Connection $c * Allows to clear the column which means the column will be excluded from * tables column list. * - * @return \Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs + * @return $this */ - public function setColumn(?Column $column = null) + public function setColumn(?Column $column) : self { $this->column = $column; return $this; } - /** - * @return Column|null - */ - public function getColumn() + public function getColumn() : ?Column { return $this->column; } /** - * @return mixed[] + * @return array */ - public function getTableColumn() + public function getTableColumn() : array { return $this->tableColumn; } - /** - * @return string - */ - public function getTable() + public function getTable() : string { return $this->table; } - /** - * @return string - */ - public function getDatabase() + public function getDatabase() : string { return $this->database; } - /** - * @return Connection - */ - public function getConnection() + public function getConnection() : Connection { return $this->connection; } - - /** - * @return AbstractPlatform - */ - public function getDatabasePlatform() - { - return $this->connection->getDatabasePlatform(); - } } diff --git a/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php index 9d24b8b9049..038da6a0a68 100644 --- a/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php @@ -1,12 +1,13 @@ */ private $sql = []; public function __construct(Column $column, Table $table, AbstractPlatform $platform) @@ -32,50 +33,35 @@ public function __construct(Column $column, Table $table, AbstractPlatform $plat $this->platform = $platform; } - /** - * @return Column - */ - public function getColumn() + public function getColumn() : Column { return $this->column; } - /** - * @return Table - */ - public function getTable() + public function getTable() : Table { return $this->table; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php index 954f77aa55a..26bad3b4888 100644 --- a/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php @@ -1,35 +1,37 @@ > */ private $columns; - /** @var mixed[] */ + /** @var array */ private $options; /** @var AbstractPlatform */ private $platform; - /** @var string[] */ + /** @var array */ private $sql = []; /** - * @param mixed[][] $columns - * @param mixed[] $options + * @param array> $columns + * @param array $options */ public function __construct(Table $table, array $columns, array $options, AbstractPlatform $platform) { @@ -39,58 +41,46 @@ public function __construct(Table $table, array $columns, array $options, Abstra $this->platform = $platform; } - /** - * @return Table - */ - public function getTable() + public function getTable() : Table { return $this->table; } /** - * @return mixed[][] + * @return array> */ - public function getColumns() + public function getColumns() : array { return $this->columns; } /** - * @return mixed[] + * @return array */ - public function getOptions() + public function getOptions() : array { return $this->options; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string|string[] $sql - * - * @return \Doctrine\DBAL\Event\SchemaCreateTableEventArgs + * @return $this */ - public function addSql($sql) + public function addSql(string ...$sql) : self { - if (is_array($sql)) { - $this->sql = array_merge($this->sql, $sql); - } else { - $this->sql[] = $sql; - } + $this->sql = array_merge($this->sql, $sql); return $this; } /** - * @return string[] + * @return array */ - public function getSql() + public function getSql() : array { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php index 387049791d2..73fe78201cd 100644 --- a/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php @@ -1,5 +1,7 @@ table; } - /** - * @return AbstractPlatform - */ - public function getPlatform() + public function getPlatform() : AbstractPlatform { return $this->platform; } /** - * @param string $sql - * - * @return \Doctrine\DBAL\Event\SchemaDropTableEventArgs + * @return $this */ - public function setSql($sql) + public function setSql(string $sql) : self { $this->sql = $sql; return $this; } - /** - * @return string|null - */ - public function getSql() + public function getSql() : ?string { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Event/SchemaEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaEventArgs.php index 0db0689c5ad..4b15c80e444 100644 --- a/lib/Doctrine/DBAL/Event/SchemaEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaEventArgs.php @@ -1,5 +1,7 @@ preventDefault = true; return $this; } - /** - * @return bool - */ - public function isDefaultPrevented() + public function isDefaultPrevented() : bool { return $this->preventDefault; } diff --git a/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php b/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php index 317f352b87a..c39e1f3b2ea 100644 --- a/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php +++ b/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php @@ -1,9 +1,10 @@ */ private $tableIndex; @@ -28,10 +29,9 @@ class SchemaIndexDefinitionEventArgs extends SchemaEventArgs private $connection; /** - * @param mixed[] $tableIndex - * @param string $table + * @param array $tableIndex */ - public function __construct(array $tableIndex, $table, Connection $connection) + public function __construct(array $tableIndex, string $table, Connection $connection) { $this->tableIndex = $tableIndex; $this->table = $table; @@ -41,52 +41,35 @@ public function __construct(array $tableIndex, $table, Connection $connection) /** * Allows to clear the index which means the index will be excluded from tables index list. * - * @return SchemaIndexDefinitionEventArgs + * @return $this */ - public function setIndex(?Index $index = null) + public function setIndex(?Index $index) : self { $this->index = $index; return $this; } - /** - * @return Index|null - */ - public function getIndex() + public function getIndex() : ?Index { return $this->index; } /** - * @return mixed[] + * @return array */ - public function getTableIndex() + public function getTableIndex() : array { return $this->tableIndex; } - /** - * @return string - */ - public function getTable() + public function getTable() : string { return $this->table; } - /** - * @return Connection - */ - public function getConnection() + public function getConnection() : Connection { return $this->connection; } - - /** - * @return AbstractPlatform - */ - public function getDatabasePlatform() - { - return $this->connection->getDatabasePlatform(); - } } diff --git a/lib/Doctrine/DBAL/Events.php b/lib/Doctrine/DBAL/Events.php index 5398d0f84c2..605afdb070a 100644 --- a/lib/Doctrine/DBAL/Events.php +++ b/lib/Doctrine/DBAL/Events.php @@ -1,5 +1,7 @@ getName(), + $type + ) + ); + } +} diff --git a/lib/Doctrine/DBAL/Exception/CommitFailedRollbackOnly.php b/lib/Doctrine/DBAL/Exception/CommitFailedRollbackOnly.php new file mode 100644 index 00000000000..dd53e900711 --- /dev/null +++ b/lib/Doctrine/DBAL/Exception/CommitFailedRollbackOnly.php @@ -0,0 +1,15 @@ +driverException = $driverException; + parent::__construct($message, $driverException->getCode(), $driverException); } /** - * Returns the driver specific error code if given. - * - * Returns null if no error code was given by the driver. - * - * @return int|string|null + * {@inheritDoc} */ - public function getErrorCode() + public function getSQLState() : ?string { - return $this->driverException->getErrorCode(); - } + $previous = $this->getPrevious(); + assert($previous instanceof DriverExceptionInterface); - /** - * Returns the SQLSTATE the driver was in at the time the error occurred, if given. - * - * Returns null if no SQLSTATE was given by the driver. - * - * @return string|null - */ - public function getSQLState() - { - return $this->driverException->getSQLState(); + return $previous->getSQLState(); } } diff --git a/lib/Doctrine/DBAL/Exception/DriverRequired.php b/lib/Doctrine/DBAL/Exception/DriverRequired.php new file mode 100644 index 00000000000..9623b2a8a51 --- /dev/null +++ b/lib/Doctrine/DBAL/Exception/DriverRequired.php @@ -0,0 +1,32 @@ +__invoke($invalidPlatform) + ) + ); + } +} diff --git a/lib/Doctrine/DBAL/Exception/InvalidWrapperClass.php b/lib/Doctrine/DBAL/Exception/InvalidWrapperClass.php new file mode 100644 index 00000000000..5c81978b120 --- /dev/null +++ b/lib/Doctrine/DBAL/Exception/InvalidWrapperClass.php @@ -0,0 +1,23 @@ +> */ private $sequences = []; /** - * @param string $generatorTableName - * * @throws DBALException */ - public function __construct(Connection $conn, $generatorTableName = 'sequences') + public function __construct(Connection $conn, string $generatorTableName = 'sequences') { $params = $conn->getParams(); if ($params['driver'] === 'pdo_sqlite') { @@ -77,13 +78,9 @@ public function __construct(Connection $conn, $generatorTableName = 'sequences') /** * Generates the next unused value for the given sequence name. * - * @param string $sequenceName - * - * @return int - * * @throws DBALException */ - public function nextValue($sequenceName) + public function nextValue(string $sequenceName) : int { if (isset($this->sequences[$sequenceName])) { $value = $this->sequences[$sequenceName]['value']; @@ -124,7 +121,7 @@ public function nextValue($sequenceName) $rows = $this->conn->executeUpdate($sql, [$sequenceName, $row['sequence_value']]); if ($rows !== 1) { - throw new DBALException('Race-condition detected while updating sequence. Aborting generation'); + throw new DBALException('Race condition detected while updating sequence. Aborting generation.'); } } else { $this->conn->insert( @@ -137,7 +134,7 @@ public function nextValue($sequenceName) $this->conn->commit(); } catch (Throwable $e) { $this->conn->rollBack(); - throw new DBALException('Error occurred while generating ID with TableGenerator, aborted generation: ' . $e->getMessage(), 0, $e); + throw new DBALException(sprintf('Error occurred while generating ID with TableGenerator, aborted generation with error: %s', $e->getMessage()), 0, $e); } return $value; diff --git a/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php b/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php index 3ec22f37c5c..12c7695eba2 100644 --- a/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php +++ b/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php @@ -1,5 +1,7 @@ generatorTableName = $generatorTableName; } @@ -26,10 +25,11 @@ public function __construct($generatorTableName = 'sequences') /** * {@inheritdoc} */ - public function acceptSchema(Schema $schema) + public function acceptSchema(Schema $schema) : void { $table = $schema->createTable($this->generatorTableName); - $table->addColumn('sequence_name', 'string'); + + $table->addColumn('sequence_name', 'string', ['length' => 255]); $table->addColumn('sequence_value', 'integer', ['default' => 1]); $table->addColumn('sequence_increment_by', 'integer', ['default' => 1]); } @@ -37,35 +37,35 @@ public function acceptSchema(Schema $schema) /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { } /** * {@inheritdoc} */ - public function acceptColumn(Table $table, Column $column) + public function acceptColumn(Table $table, Column $column) : void { } /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { } /** * {@inheritdoc} */ - public function acceptIndex(Table $table, Index $index) + public function acceptIndex(Table $table, Index $index) : void { } /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { } } diff --git a/lib/Doctrine/DBAL/LockMode.php b/lib/Doctrine/DBAL/LockMode.php index 14e81432b43..9c2f901d87c 100644 --- a/lib/Doctrine/DBAL/LockMode.php +++ b/lib/Doctrine/DBAL/LockMode.php @@ -1,5 +1,7 @@ enabled) { return; @@ -45,7 +47,7 @@ public function startQuery($sql, ?array $params = null, ?array $types = null) /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { if (! $this->enabled) { return; diff --git a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php index 657abb4d378..754b34269d7 100644 --- a/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php +++ b/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php @@ -1,5 +1,7 @@ */ private $loggers = []; /** - * Adds a logger in the chain. - * - * @return void + * @param iterable $loggers */ - public function addLogger(SQLLogger $logger) + public function __construct(iterable $loggers = []) { - $this->loggers[] = $logger; + $this->loggers = $loggers; } /** * {@inheritdoc} */ - public function startQuery($sql, ?array $params = null, ?array $types = null) + public function startQuery(string $sql, array $params = [], array $types = []) : void { foreach ($this->loggers as $logger) { $logger->startQuery($sql, $params, $types); @@ -33,7 +33,7 @@ public function startQuery($sql, ?array $params = null, ?array $types = null) /** * {@inheritdoc} */ - public function stopQuery() + public function stopQuery() : void { foreach ($this->loggers as $logger) { $logger->stopQuery(); diff --git a/lib/Doctrine/DBAL/Logging/NullLogger.php b/lib/Doctrine/DBAL/Logging/NullLogger.php new file mode 100644 index 00000000000..6269b6f610c --- /dev/null +++ b/lib/Doctrine/DBAL/Logging/NullLogger.php @@ -0,0 +1,27 @@ +_eventManager = $eventManager; } /** * Gets the EventManager used by the Platform. - * - * @return EventManager */ - public function getEventManager() + public function getEventManager() : ?EventManager { return $this->_eventManager; } @@ -176,61 +117,47 @@ public function getEventManager() * Returns the SQL snippet that declares a boolean column. * * @param mixed[] $columnDef - * - * @return string */ - abstract public function getBooleanTypeDeclarationSQL(array $columnDef); + abstract public function getBooleanTypeDeclarationSQL(array $columnDef) : string; /** * Returns the SQL snippet that declares a 4 byte integer column. * * @param mixed[] $columnDef - * - * @return string */ - abstract public function getIntegerTypeDeclarationSQL(array $columnDef); + abstract public function getIntegerTypeDeclarationSQL(array $columnDef) : string; /** * Returns the SQL snippet that declares an 8 byte integer column. * * @param mixed[] $columnDef - * - * @return string */ - abstract public function getBigIntTypeDeclarationSQL(array $columnDef); + abstract public function getBigIntTypeDeclarationSQL(array $columnDef) : string; /** * Returns the SQL snippet that declares a 2 byte integer column. * * @param mixed[] $columnDef - * - * @return string */ - abstract public function getSmallIntTypeDeclarationSQL(array $columnDef); + abstract public function getSmallIntTypeDeclarationSQL(array $columnDef) : string; /** * Returns the SQL snippet that declares common properties of an integer column. * * @param mixed[] $columnDef - * - * @return string */ - abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef); + abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string; /** * Lazy load Doctrine Type Mappings. - * - * @return void */ - abstract protected function initializeDoctrineTypeMappings(); + abstract protected function initializeDoctrineTypeMappings() : void; /** * Initializes Doctrine Type Mappings with the platform defaults * and with all additional type mappings. - * - * @return void */ - private function initializeAllDoctrineTypeMappings() + private function initializeAllDoctrineTypeMappings() : void { $this->initializeDoctrineTypeMappings(); @@ -242,61 +169,39 @@ private function initializeAllDoctrineTypeMappings() } /** - * Returns the SQL snippet used to declare a VARCHAR column type. + * Returns the SQL snippet used to declare a string column type. * - * @param mixed[] $field + * @param array $column The column definition. * - * @return string + * @throws ColumnLengthRequired */ - public function getVarcharTypeDeclarationSQL(array $field) + public function getStringTypeDeclarationSQL(array $column) : string { - if (! isset($field['length'])) { - $field['length'] = $this->getVarcharDefaultLength(); - } - - $fixed = $field['fixed'] ?? false; + $length = $column['length'] ?? null; - $maxLength = $fixed - ? $this->getCharMaxLength() - : $this->getVarcharMaxLength(); - - if ($field['length'] > $maxLength) { - return $this->getClobTypeDeclarationSQL($field); + if (empty($column['fixed'])) { + return $this->getVarcharTypeDeclarationSQLSnippet($length); } - return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed); + return $this->getCharTypeDeclarationSQLSnippet($length); } /** - * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. + * Returns the SQL snippet used to declare a binary string column type. * - * @param mixed[] $field The column definition. + * @param array $column The column definition. * - * @return string + * @throws ColumnLengthRequired */ - public function getBinaryTypeDeclarationSQL(array $field) + public function getBinaryTypeDeclarationSQL(array $column) : string { - if (! isset($field['length'])) { - $field['length'] = $this->getBinaryDefaultLength(); - } - - $fixed = $field['fixed'] ?? false; + $length = $column['length'] ?? null; - $maxLength = $this->getBinaryMaxLength(); - - if ($field['length'] > $maxLength) { - if ($maxLength > 0) { - @trigger_error(sprintf( - 'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.', - $field['length'], - $maxLength - ), E_USER_DEPRECATED); - } - - return $this->getBlobTypeDeclarationSQL($field); + if (empty($column['fixed'])) { + return $this->getVarbinaryTypeDeclarationSQLSnippet($length); } - return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed); + return $this->getBinaryTypeDeclarationSQLSnippet($length); } /** @@ -305,16 +210,16 @@ public function getBinaryTypeDeclarationSQL(array $field) * By default this maps directly to a CHAR(36) and only maps to more * special datatypes when the underlying databases support this datatype. * - * @param mixed[] $field + * @param array $column The column definition. * - * @return string + * @throws DBALException */ - public function getGuidTypeDeclarationSQL(array $field) + public function getGuidTypeDeclarationSQL(array $column) : string { - $field['length'] = 36; - $field['fixed'] = true; + $column['length'] = 36; + $column['fixed'] = true; - return $this->getVarcharTypeDeclarationSQL($field); + return $this->getStringTypeDeclarationSQL($column); } /** @@ -324,83 +229,112 @@ public function getGuidTypeDeclarationSQL(array $field) * special datatypes when the underlying databases support this datatype. * * @param mixed[] $field - * - * @return string */ - public function getJsonTypeDeclarationSQL(array $field) + public function getJsonTypeDeclarationSQL(array $field) : string { return $this->getClobTypeDeclarationSQL($field); } /** - * @param int $length - * @param bool $fixed + * @param int|null $length The length of the column in characters + * or NULL if the length should be omitted. * - * @return string + * @throws ColumnLengthRequired + */ + protected function getCharTypeDeclarationSQLSnippet(?int $length) : string + { + $sql = 'CHAR'; + + if ($length !== null) { + $sql .= sprintf('(%d)', $length); + } + + return $sql; + } + + /** + * @param int|null $length The length of the column in characters + * or NULL if the length should be omitted. * - * @throws DBALException If not supported on this platform. + * @throws ColumnLengthRequired */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarcharTypeDeclarationSQLSnippet(?int $length) : string { - throw DBALException::notSupported('VARCHARs not supported by Platform.'); + if ($length === null) { + throw ColumnLengthRequired::new($this, 'VARCHAR'); + } + + return sprintf('VARCHAR(%d)', $length); } /** - * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. + * Returns the SQL snippet used to declare a fixed length binary column type. * - * @param int $length The length of the column. - * @param bool $fixed Whether the column length is fixed. + * @param int|null $length The length of the column in bytes + * or NULL if the length should be omitted. + * + * @throws ColumnLengthRequired + */ + protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string + { + $sql = 'BINARY'; + + if ($length !== null) { + $sql .= sprintf('(%d)', $length); + } + + return $sql; + } + + /** + * Returns the SQL snippet used to declare a variable length binary column type. * - * @return string + * @param int|null $length The length of the column in bytes + * or NULL if the length should be omitted. * - * @throws DBALException If not supported on this platform. + * @throws ColumnLengthRequired */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string { - throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.'); + if ($length === null) { + throw ColumnLengthRequired::new($this, 'VARBINARY'); + } + + return sprintf('VARBINARY(%d)', $length); } /** * Returns the SQL snippet used to declare a CLOB column type. * * @param mixed[] $field - * - * @return string */ - abstract public function getClobTypeDeclarationSQL(array $field); + abstract public function getClobTypeDeclarationSQL(array $field) : string; /** * Returns the SQL Snippet used to declare a BLOB column type. * * @param mixed[] $field - * - * @return string */ - abstract public function getBlobTypeDeclarationSQL(array $field); + abstract public function getBlobTypeDeclarationSQL(array $field) : string; /** * Gets the name of the platform. - * - * @return string */ - abstract public function getName(); + abstract public function getName() : string; /** * Registers a doctrine type to be used in conjunction with a column type of this platform. * - * @param string $dbType - * @param string $doctrineType - * * @throws DBALException If the type is not found. */ - public function registerDoctrineTypeMapping($dbType, $doctrineType) + public function registerDoctrineTypeMapping(string $dbType, string $doctrineType) : void { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); } if (! Types\Type::hasType($doctrineType)) { - throw DBALException::typeNotFound($doctrineType); + throw TypeNotFound::new($doctrineType); } $dbType = strtolower($dbType); @@ -418,13 +352,9 @@ public function registerDoctrineTypeMapping($dbType, $doctrineType) /** * Gets the Doctrine type that is mapped for the given database column type. * - * @param string $dbType - * - * @return string - * * @throws DBALException */ - public function getDoctrineTypeMapping($dbType) + public function getDoctrineTypeMapping(string $dbType) : string { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); @@ -433,7 +363,11 @@ public function getDoctrineTypeMapping($dbType) $dbType = strtolower($dbType); if (! isset($this->doctrineTypeMapping[$dbType])) { - throw new DBALException('Unknown database type ' . $dbType . ' requested, ' . static::class . ' may not support it.'); + throw new DBALException(sprintf( + 'Unknown database type "%s" requested, %s may not support it.', + $dbType, + static::class + )); } return $this->doctrineTypeMapping[$dbType]; @@ -441,12 +375,8 @@ public function getDoctrineTypeMapping($dbType) /** * Checks if a database type is currently supported by this platform. - * - * @param string $dbType - * - * @return bool */ - public function hasDoctrineTypeMappingFor($dbType) + public function hasDoctrineTypeMappingFor(string $dbType) : bool { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); @@ -459,10 +389,8 @@ public function hasDoctrineTypeMappingFor($dbType) /** * Initializes the Doctrine Type comments instance variable for in_array() checks. - * - * @return void */ - protected function initializeCommentedDoctrineTypes() + protected function initializeCommentedDoctrineTypes() : void { $this->doctrineTypeComments = []; @@ -479,10 +407,8 @@ protected function initializeCommentedDoctrineTypes() /** * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type? - * - * @return bool */ - public function isCommentedDoctrineType(Type $doctrineType) + public function isCommentedDoctrineType(Type $doctrineType) : bool { if ($this->doctrineTypeComments === null) { $this->initializeCommentedDoctrineTypes(); @@ -497,10 +423,8 @@ public function isCommentedDoctrineType(Type $doctrineType) * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements. * * @param string|Type $doctrineType - * - * @return void */ - public function markDoctrineTypeCommented($doctrineType) + public function markDoctrineTypeCommented($doctrineType) : void { if ($this->doctrineTypeComments === null) { $this->initializeCommentedDoctrineTypes(); @@ -513,20 +437,16 @@ public function markDoctrineTypeCommented($doctrineType) /** * Gets the comment to append to a column comment that helps parsing this type in reverse engineering. - * - * @return string */ - public function getDoctrineTypeComment(Type $doctrineType) + public function getDoctrineTypeComment(Type $doctrineType) : string { return '(DC2Type:' . $doctrineType->getName() . ')'; } /** * Gets the comment of a passed column modified by potential doctrine type comment hints. - * - * @return string|null */ - protected function getColumnComment(Column $column) + protected function getColumnComment(Column $column) : ?string { $comment = $column->getComment(); @@ -539,88 +459,34 @@ protected function getColumnComment(Column $column) /** * Gets the character used for identifier quoting. - * - * @return string */ - public function getIdentifierQuoteCharacter() + public function getIdentifierQuoteCharacter() : string { return '"'; } /** * Gets the string portion that starts an SQL comment. - * - * @return string */ - public function getSqlCommentStartString() + public function getSqlCommentStartString() : string { return '--'; } /** * Gets the string portion that ends an SQL comment. - * - * @return string */ - public function getSqlCommentEndString() + public function getSqlCommentEndString() : string { return "\n"; } - /** - * Gets the maximum length of a char field. - */ - public function getCharMaxLength() : int - { - return $this->getVarcharMaxLength(); - } - - /** - * Gets the maximum length of a varchar field. - * - * @return int - */ - public function getVarcharMaxLength() - { - return 4000; - } - - /** - * Gets the default length of a varchar field. - * - * @return int - */ - public function getVarcharDefaultLength() - { - return 255; - } - - /** - * Gets the maximum length of a binary field. - * - * @return int - */ - public function getBinaryMaxLength() - { - return 4000; - } - - /** - * Gets the default length of a binary field. - * - * @return int - */ - public function getBinaryDefaultLength() - { - return 255; - } - /** * Gets all SQL wildcard characters of the platform. * * @return string[] */ - public function getWildcards() + public function getWildcards() : array { return ['%', '_']; } @@ -628,39 +494,21 @@ public function getWildcards() /** * Returns the regular expression operator. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getRegexpExpression() + public function getRegexpExpression() : string { - throw DBALException::notSupported(__METHOD__); - } - - /** - * Returns the global unique identifier expression. - * - * @deprecated Use application-generated UUIDs instead - * - * @return string - * - * @throws DBALException If not supported on this platform. - */ - public function getGuidExpression() - { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL snippet to get the average value of a column. * - * @param string $column The column to use. - * - * @return string Generated SQL including an AVG aggregate function. + * @param string $value SQL expression producing the value. */ - public function getAvgExpression($column) + public function getAvgExpression(string $value) : string { - return 'AVG(' . $column . ')'; + return 'AVG(' . $value . ')'; } /** @@ -668,115 +516,97 @@ public function getAvgExpression($column) * * If a '*' is used instead of a column the number of selected rows is returned. * - * @param string|int $column The column to use. - * - * @return string Generated SQL including a COUNT aggregate function. + * @param string $expression The expression to count. */ - public function getCountExpression($column) + public function getCountExpression(string $expression) : string { - return 'COUNT(' . $column . ')'; + return 'COUNT(' . $expression . ')'; } /** - * Returns the SQL snippet to get the highest value of a column. + * Returns the SQL snippet to get the maximum value in a set of values. * - * @param string $column The column to use. - * - * @return string Generated SQL including a MAX aggregate function. + * @param string $value SQL expression producing the value. */ - public function getMaxExpression($column) + public function getMaxExpression(string $value) : string { - return 'MAX(' . $column . ')'; + return 'MAX(' . $value . ')'; } /** - * Returns the SQL snippet to get the lowest value of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the minimum value in a set of values. * - * @return string Generated SQL including a MIN aggregate function. + * @param string $value SQL expression producing the value. */ - public function getMinExpression($column) + public function getMinExpression(string $value) : string { - return 'MIN(' . $column . ')'; + return 'MIN(' . $value . ')'; } /** - * Returns the SQL snippet to get the total sum of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the total sum of the values in a set. * - * @return string Generated SQL including a SUM aggregate function. + * @param string $value SQL expression producing the value. */ - public function getSumExpression($column) + public function getSumExpression(string $value) : string { - return 'SUM(' . $column . ')'; + return 'SUM(' . $value . ')'; } // scalar functions /** - * Returns the SQL snippet to get the md5 sum of a field. + * Returns the SQL snippet to get the md5 sum of the value. * * Note: Not SQL92, but common functionality. * - * @param string $column - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getMd5Expression($column) + public function getMd5Expression(string $string) : string { - return 'MD5(' . $column . ')'; + return 'MD5(' . $string . ')'; } /** * Returns the SQL snippet to get the length of a text field. * - * @param string $column - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLengthExpression($column) + public function getLengthExpression(string $string) : string { - return 'LENGTH(' . $column . ')'; + return 'LENGTH(' . $string . ')'; } /** - * Returns the SQL snippet to get the squared value of a column. - * - * @param string $column The column to use. + * Returns the SQL snippet to get the square root of the value. * - * @return string Generated SQL including an SQRT aggregate function. + * @param string $number SQL expression producing the number. */ - public function getSqrtExpression($column) + public function getSqrtExpression(string $number) : string { - return 'SQRT(' . $column . ')'; + return 'SQRT(' . $number . ')'; } /** - * Returns the SQL snippet to round a numeric field to the number of decimals specified. + * Returns the SQL snippet to round a number to the number of decimals specified. * - * @param string $column - * @param int $decimals - * - * @return string + * @param string $number SQL expression producing the number to round. + * @param string $decimals SQL expression producing the number of decimals. */ - public function getRoundExpression($column, $decimals = 0) + public function getRoundExpression(string $number, string $decimals = '0') : string { - return 'ROUND(' . $column . ', ' . $decimals . ')'; + return 'ROUND(' . $number . ', ' . $decimals . ')'; } /** - * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2. - * - * @param string $expression1 - * @param string $expression2 + * Returns the SQL snippet to get the remainder of the operation of division of dividend by divisor. * - * @return string + * @param string $dividend SQL expression producing the dividend. + * @param string $divisor SQL expression producing the divisor. */ - public function getModExpression($expression1, $expression2) + public function getModExpression(string $dividend, string $divisor) : string { - return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; + return 'MOD(' . $dividend . ', ' . $divisor . ')'; } /** @@ -784,243 +614,218 @@ public function getModExpression($expression1, $expression2) * * @param string $str The expression to apply the trim to. * @param int $mode The position of the trim (leading/trailing/both). - * @param string|bool $char The char to trim, has to be quoted already. Defaults to space. + * @param string|null $char The char to trim, has to be quoted already. Defaults to space. * - * @return string + * @throws InvalidArgumentException */ - public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - $expression = ''; + $tokens = []; switch ($mode) { + case TrimMode::UNSPECIFIED: + break; + case TrimMode::LEADING: - $expression = 'LEADING '; + $tokens[] = 'LEADING'; break; case TrimMode::TRAILING: - $expression = 'TRAILING '; + $tokens[] = 'TRAILING'; break; case TrimMode::BOTH: - $expression = 'BOTH '; + $tokens[] = 'BOTH'; break; + + default: + throw new InvalidArgumentException( + sprintf( + 'The value of $mode is expected to be one of the TrimMode constants, %d given.', + $mode + ) + ); } - if ($char !== false) { - $expression .= $char . ' '; + if ($char !== null) { + $tokens[] = $char; } - if ($mode || $char !== false) { - $expression .= 'FROM '; + if (count($tokens) > 0) { + $tokens[] = 'FROM'; } - return 'TRIM(' . $expression . $str . ')'; + $tokens[] = $str; + + return sprintf('TRIM(%s)', implode(' ', $tokens)); } /** - * Returns the SQL snippet to trim trailing space characters from the expression. + * Returns the SQL snippet to trim trailing space characters from the string. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getRtrimExpression($str) + public function getRtrimExpression(string $string) : string { - return 'RTRIM(' . $str . ')'; + return 'RTRIM(' . $string . ')'; } /** - * Returns the SQL snippet to trim leading space characters from the expression. - * - * @param string $str Literal string or column name. + * Returns the SQL snippet to trim leading space characters from the string. * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLtrimExpression($str) + public function getLtrimExpression(string $string) : string { - return 'LTRIM(' . $str . ')'; + return 'LTRIM(' . $string . ')'; } /** - * Returns the SQL snippet to change all characters from the expression to uppercase, + * Returns the SQL snippet to change all characters from the string to uppercase, * according to the current character set mapping. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getUpperExpression($str) + public function getUpperExpression(string $string) : string { - return 'UPPER(' . $str . ')'; + return 'UPPER(' . $string . ')'; } /** - * Returns the SQL snippet to change all characters from the expression to lowercase, + * Returns the SQL snippet to change all characters from the string to lowercase, * according to the current character set mapping. * - * @param string $str Literal string or column name. - * - * @return string + * @param string $string SQL expression producing the string. */ - public function getLowerExpression($str) + public function getLowerExpression(string $string) : string { - return 'LOWER(' . $str . ')'; + return 'LOWER(' . $string . ')'; } /** - * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str. - * - * @param string $str Literal string. - * @param string $substr Literal string to find. - * @param int|false $startPos Position to start at, beginning of string by default. + * Returns the SQL snippet to get the position of the first occurrence of the substring in the string. * - * @return string + * @param string $string SQL expression producing the string to locate the substring in. + * @param string $substring SQL expression producing the substring to locate. + * @param string|null $start SQL expression producing the position to start at. + * Defaults to the beginning of the string. * * @throws DBALException If not supported on this platform. */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL snippet to get the current system date. - * - * @return string */ - public function getNowExpression() + public function getNowExpression() : string { return 'NOW()'; } /** - * Returns a SQL snippet to get a substring inside an SQL statement. + * Returns an SQL snippet to get a substring inside the string. * * Note: Not SQL92, but common functionality. * - * SQLite only supports the 2 parameter variant of this function. - * - * @param string $value An sql string literal or column name/alias. - * @param int $from Where to start the substring portion. - * @param int|null $length The substring portion length. - * - * @return string + * @param string $string SQL expression producing the string from which a substring should be extracted. + * @param string $start SQL expression producing the position to start at, + * @param string|null $length SQL expression producing the length of the substring portion to be returned. + * By default, the entire substring is returned. */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; + return sprintf('SUBSTRING(%s FROM %s)', $string, $start); } - return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; + return sprintf('SUBSTRING(%s FROM %s FOR %s)', $string, $start, $length); } /** - * Returns a SQL snippet to concatenate the given expressions. - * - * Accepts an arbitrary number of string parameters. Each parameter must contain an expression. + * Returns a SQL snippet to concatenate the given strings. * - * @return string + * @param string[] ...$string */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - return implode(' || ', func_get_args()); + return implode(' || ', $string); } /** * Returns the SQL for a logical not. * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * $q->select('*')->from('table') - * ->where($e->eq('id', $e->not('null')); - * - * - * @param string $expression - * - * @return string The logical expression. + * @param string $value SQL expression producing the value to negate. */ - public function getNotExpression($expression) + public function getNotExpression(string $value) : string { - return 'NOT(' . $expression . ')'; + return 'NOT(' . $value . ')'; } /** * Returns the SQL that checks if an expression is null. * - * @param string $expression The expression that should be compared to null. - * - * @return string The logical expression. + * @param string $value SQL expression producing the to be compared to null. */ - public function getIsNullExpression($expression) + public function getIsNullExpression(string $value) : string { - return $expression . ' IS NULL'; + return $value . ' IS NULL'; } /** * Returns the SQL that checks if an expression is not null. * - * @param string $expression The expression that should be compared to null. - * - * @return string The logical expression. + * @param string $value SQL expression producing the to be compared to null. */ - public function getIsNotNullExpression($expression) + public function getIsNotNullExpression(string $value) : string { - return $expression . ' IS NOT NULL'; + return $value . ' IS NOT NULL'; } /** * Returns the SQL that checks if an expression evaluates to a value between two values. * - * The parameter $expression is checked if it is between $value1 and $value2. + * The parameter $value is checked if it is between $min and $max. * * Note: There is a slight difference in the way BETWEEN works on some databases. * http://www.w3schools.com/sql/sql_between.asp. If you want complete database * independence you should avoid using between(). * - * @param string $expression The value to compare to. - * @param string $value1 The lower value to compare with. - * @param string $value2 The higher value to compare with. - * - * @return string The logical expression. + * @param string $value SQL expression producing the value to compare. + * @param string $min SQL expression producing the lower value to compare with. + * @param string $max SQL expression producing the higher value to compare with. */ - public function getBetweenExpression($expression, $value1, $value2) + public function getBetweenExpression(string $value, string $min, string $max) : string { - return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2; + return $value . ' BETWEEN ' . $min . ' AND ' . $max; } /** * Returns the SQL to get the arccosine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getAcosExpression($value) + public function getAcosExpression(string $number) : string { - return 'ACOS(' . $value . ')'; + return 'ACOS(' . $number . ')'; } /** * Returns the SQL to get the sine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getSinExpression($value) + public function getSinExpression(string $number) : string { - return 'SIN(' . $value . ')'; + return 'SIN(' . $number . ')'; } /** * Returns the SQL to get the PI value. - * - * @return string */ - public function getPiExpression() + public function getPiExpression() : string { return 'PI()'; } @@ -1028,13 +833,11 @@ public function getPiExpression() /** * Returns the SQL to get the cosine of a value. * - * @param string $value - * - * @return string + * @param string $number SQL expression producing the number. */ - public function getCosExpression($value) + public function getCosExpression(string $number) : string { - return 'COS(' . $value . ')'; + return 'COS(' . $number . ')'; } /** @@ -1042,29 +845,22 @@ public function getCosExpression($value) * * Computes diff = date1 - date2. * - * @param string $date1 - * @param string $date2 - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL to add the number of given seconds to a date. * - * @param string $date - * @param int $seconds - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $seconds SQL expression producing the number of seconds. * * @throws DBALException If not supported on this platform. */ - public function getDateAddSecondsExpression($date, $seconds) + public function getDateAddSecondsExpression(string $date, string $seconds) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND); } @@ -1072,14 +868,12 @@ public function getDateAddSecondsExpression($date, $seconds) /** * Returns the SQL to subtract the number of given seconds from a date. * - * @param string $date - * @param int $seconds - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $seconds SQL expression producing the number of seconds. * * @throws DBALException If not supported on this platform. */ - public function getDateSubSecondsExpression($date, $seconds) + public function getDateSubSecondsExpression(string $date, string $seconds) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND); } @@ -1087,14 +881,12 @@ public function getDateSubSecondsExpression($date, $seconds) /** * Returns the SQL to add the number of given minutes to a date. * - * @param string $date - * @param int $minutes - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $minutes SQL expression producing the number of minutes. * * @throws DBALException If not supported on this platform. */ - public function getDateAddMinutesExpression($date, $minutes) + public function getDateAddMinutesExpression(string $date, string $minutes) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE); } @@ -1102,14 +894,12 @@ public function getDateAddMinutesExpression($date, $minutes) /** * Returns the SQL to subtract the number of given minutes from a date. * - * @param string $date - * @param int $minutes - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $minutes SQL expression producing the number of minutes. * * @throws DBALException If not supported on this platform. */ - public function getDateSubMinutesExpression($date, $minutes) + public function getDateSubMinutesExpression(string $date, string $minutes) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE); } @@ -1117,14 +907,12 @@ public function getDateSubMinutesExpression($date, $minutes) /** * Returns the SQL to add the number of given hours to a date. * - * @param string $date - * @param int $hours - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $hours SQL expression producing the number of hours. * * @throws DBALException If not supported on this platform. */ - public function getDateAddHourExpression($date, $hours) + public function getDateAddHourExpression(string $date, string $hours) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR); } @@ -1132,14 +920,12 @@ public function getDateAddHourExpression($date, $hours) /** * Returns the SQL to subtract the number of given hours to a date. * - * @param string $date - * @param int $hours - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $hours SQL expression producing the number of hours. * * @throws DBALException If not supported on this platform. */ - public function getDateSubHourExpression($date, $hours) + public function getDateSubHourExpression(string $date, string $hours) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR); } @@ -1147,14 +933,12 @@ public function getDateSubHourExpression($date, $hours) /** * Returns the SQL to add the number of given days to a date. * - * @param string $date - * @param int $days - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $days SQL expression producing the number of days. * * @throws DBALException If not supported on this platform. */ - public function getDateAddDaysExpression($date, $days) + public function getDateAddDaysExpression(string $date, string $days) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY); } @@ -1162,14 +946,12 @@ public function getDateAddDaysExpression($date, $days) /** * Returns the SQL to subtract the number of given days to a date. * - * @param string $date - * @param int $days - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $days SQL expression producing the number of days. * * @throws DBALException If not supported on this platform. */ - public function getDateSubDaysExpression($date, $days) + public function getDateSubDaysExpression(string $date, string $days) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY); } @@ -1177,14 +959,12 @@ public function getDateSubDaysExpression($date, $days) /** * Returns the SQL to add the number of given weeks to a date. * - * @param string $date - * @param int $weeks - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $weeks SQL expression producing the number of weeks. * * @throws DBALException If not supported on this platform. */ - public function getDateAddWeeksExpression($date, $weeks) + public function getDateAddWeeksExpression(string $date, string $weeks) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK); } @@ -1192,14 +972,12 @@ public function getDateAddWeeksExpression($date, $weeks) /** * Returns the SQL to subtract the number of given weeks from a date. * - * @param string $date - * @param int $weeks - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $weeks SQL expression producing the number of weeks. * * @throws DBALException If not supported on this platform. */ - public function getDateSubWeeksExpression($date, $weeks) + public function getDateSubWeeksExpression(string $date, string $weeks) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK); } @@ -1207,14 +985,12 @@ public function getDateSubWeeksExpression($date, $weeks) /** * Returns the SQL to add the number of given months to a date. * - * @param string $date - * @param int $months - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $months SQL expression producing the number of months. * * @throws DBALException If not supported on this platform. */ - public function getDateAddMonthExpression($date, $months) + public function getDateAddMonthExpression(string $date, string $months) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH); } @@ -1222,14 +998,12 @@ public function getDateAddMonthExpression($date, $months) /** * Returns the SQL to subtract the number of given months to a date. * - * @param string $date - * @param int $months - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $months SQL expression producing the number of months. * * @throws DBALException If not supported on this platform. */ - public function getDateSubMonthExpression($date, $months) + public function getDateSubMonthExpression(string $date, string $months) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH); } @@ -1237,14 +1011,12 @@ public function getDateSubMonthExpression($date, $months) /** * Returns the SQL to add the number of given quarters to a date. * - * @param string $date - * @param int $quarters - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $quarters SQL expression producing the number of quarters. * * @throws DBALException If not supported on this platform. */ - public function getDateAddQuartersExpression($date, $quarters) + public function getDateAddQuartersExpression(string $date, string $quarters) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER); } @@ -1252,14 +1024,12 @@ public function getDateAddQuartersExpression($date, $quarters) /** * Returns the SQL to subtract the number of given quarters from a date. * - * @param string $date - * @param int $quarters - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $quarters SQL expression producing the number of quarters. * * @throws DBALException If not supported on this platform. */ - public function getDateSubQuartersExpression($date, $quarters) + public function getDateSubQuartersExpression(string $date, string $quarters) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER); } @@ -1267,14 +1037,12 @@ public function getDateSubQuartersExpression($date, $quarters) /** * Returns the SQL to add the number of given years to a date. * - * @param string $date - * @param int $years - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $years SQL expression producing the number of years. * * @throws DBALException If not supported on this platform. */ - public function getDateAddYearsExpression($date, $years) + public function getDateAddYearsExpression(string $date, string $years) : string { return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR); } @@ -1282,14 +1050,12 @@ public function getDateAddYearsExpression($date, $years) /** * Returns the SQL to subtract the number of given years from a date. * - * @param string $date - * @param int $years - * - * @return string + * @param string $date SQL expression producing the date. + * @param string $years SQL expression producing the number of years. * * @throws DBALException If not supported on this platform. */ - public function getDateSubYearsExpression($date, $years) + public function getDateSubYearsExpression(string $date, string $years) : string { return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR); } @@ -1297,30 +1063,40 @@ public function getDateSubYearsExpression($date, $years) /** * Returns the SQL for a date arithmetic expression. * - * @param string $date The column or literal representing a date to perform the arithmetic operation on. + * @param string $date SQL expression representing a date to perform the arithmetic operation on. * @param string $operator The arithmetic operator (+ or -). - * @param int $interval The interval that shall be calculated into the date. + * @param string $interval SQL expression representing the value of the interval that shall be calculated + * into the date. * @param string $unit The unit of the interval that shall be calculated into the date. * One of the DATE_INTERVAL_UNIT_* constants. * - * @return string - * * @throws DBALException If not supported on this platform. */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * Returns the SQL bit AND comparison expression. + * Generates the SQL expression which represents the given date interval multiplied by a number * - * @param string $value1 - * @param string $value2 + * @param string $interval SQL expression describing the interval value + * @param int $multiplier Interval multiplier * - * @return string + * @throws DBALException */ - public function getBitAndComparisonExpression($value1, $value2) + protected function multiplyInterval(string $interval, int $multiplier) : string + { + return sprintf('(%s * %d)', $interval, $multiplier); + } + + /** + * Returns the SQL bit AND comparison expression. + * + * @param string $value1 SQL expression producing the first value. + * @param string $value2 SQL expression producing the second value. + */ + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . ' & ' . $value2 . ')'; } @@ -1328,22 +1104,18 @@ public function getBitAndComparisonExpression($value1, $value2) /** * Returns the SQL bit OR comparison expression. * - * @param string $value1 - * @param string $value2 - * - * @return string + * @param string $value1 SQL expression producing the first value. + * @param string $value2 SQL expression producing the second value. */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . ' | ' . $value2 . ')'; } /** * Returns the FOR UPDATE expression. - * - * @return string */ - public function getForUpdateSQL() + public function getForUpdateSQL() : string { return 'FOR UPDATE'; } @@ -1354,10 +1126,8 @@ public function getForUpdateSQL() * @param string $fromClause The FROM clause to append the hint for the given lock mode to. * @param int|null $lockMode One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will * be appended to the FROM clause. - * - * @return string */ - public function appendLockHint($fromClause, $lockMode) + public function appendLockHint(string $fromClause, ?int $lockMode) : string { return $fromClause; } @@ -1367,10 +1137,8 @@ public function appendLockHint($fromClause, $lockMode) * * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database * vendors allow to lighten this constraint up to be a real read lock. - * - * @return string */ - public function getReadLockSQL() + public function getReadLockSQL() : string { return $this->getForUpdateSQL(); } @@ -1379,10 +1147,8 @@ public function getReadLockSQL() * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows. * * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard. - * - * @return string */ - public function getWriteLockSQL() + public function getWriteLockSQL() : string { return $this->getForUpdateSQL(); } @@ -1391,10 +1157,8 @@ public function getWriteLockSQL() * Returns the SQL snippet to drop an existing database. * * @param string $database The name of the database that should be dropped. - * - * @return string */ - public function getDropDatabaseSQL($database) + public function getDropDatabaseSQL(string $database) : string { return 'DROP DATABASE ' . $database; } @@ -1404,11 +1168,9 @@ public function getDropDatabaseSQL($database) * * @param Table|string $table * - * @return string - * * @throws InvalidArgumentException */ - public function getDropTableSQL($table) + public function getDropTableSQL($table) : string { $tableArg = $table; @@ -1428,7 +1190,7 @@ public function getDropTableSQL($table) $sql = $eventArgs->getSql(); if ($sql === null) { - throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL'); + throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL.'); } return $sql; @@ -1442,10 +1204,8 @@ public function getDropTableSQL($table) * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction. * * @param Table|string $table - * - * @return string */ - public function getDropTemporaryTableSQL($table) + public function getDropTemporaryTableSQL($table) : string { return $this->getDropTableSQL($table); } @@ -1456,11 +1216,9 @@ public function getDropTemporaryTableSQL($table) * @param Index|string $index * @param Table|string $table * - * @return string - * * @throws InvalidArgumentException */ - public function getDropIndexSQL($index, $table = null) + public function getDropIndexSQL($index, $table = null) : string { if ($index instanceof Index) { $index = $index->getQuotedName($this); @@ -1476,10 +1234,8 @@ public function getDropIndexSQL($index, $table = null) * * @param Constraint|string $constraint * @param Table|string $table - * - * @return string */ - public function getDropConstraintSQL($constraint, $table) + public function getDropConstraintSQL($constraint, $table) : string { if (! $constraint instanceof Constraint) { $constraint = new Identifier($constraint); @@ -1500,10 +1256,8 @@ public function getDropConstraintSQL($constraint, $table) * * @param ForeignKeyConstraint|string $foreignKey * @param Table|string $table - * - * @return string */ - public function getDropForeignKeySQL($foreignKey, $table) + public function getDropForeignKeySQL($foreignKey, $table) : string { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); @@ -1523,21 +1277,14 @@ public function getDropForeignKeySQL($foreignKey, $table) * Returns the SQL statement(s) to create a table with the specified name, columns and constraints * on this platform. * - * @param int $createFlags - * - * @return string[] The sequence of SQL statements. + * @return array The sequence of SQL statements. * * @throws DBALException - * @throws InvalidArgumentException */ - public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES) + public function getCreateTableSQL(Table $table, int $createFlags = self::CREATE_INDEXES) : array { - if (! is_int($createFlags)) { - throw new InvalidArgumentException('Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.'); - } - if (count($table->getColumns()) === 0) { - throw DBALException::noColumnsSpecifiedForTable($table->getName()); + throw NoColumnsSpecifiedForTable::new($table->getName()); } $tableName = $table->getQuotedName($this); @@ -1546,15 +1293,30 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE $options['indexes'] = []; $options['primary'] = []; - if (($createFlags&self::CREATE_INDEXES) > 0) { + if (($createFlags & self::CREATE_INDEXES) > 0) { foreach ($table->getIndexes() as $index) { /** @var $index Index */ - if ($index->isPrimary()) { - $options['primary'] = $index->getQuotedColumns($this); - $options['primary_index'] = $index; - } else { + if (! $index->isPrimary()) { $options['indexes'][$index->getQuotedName($this)] = $index; + + continue; } + + $options['primary'] = $index->getQuotedColumns($this); + $options['primary_index'] = $index; + } + + foreach ($table->getUniqueConstraints() as $uniqueConstraint) { + /** @var UniqueConstraint $uniqueConstraint */ + $options['uniqueConstraints'][$uniqueConstraint->getQuotedName($this)] = $uniqueConstraint; + } + } + + if (($createFlags & self::CREATE_FOREIGNKEYS) > 0) { + $options['foreignKeys'] = []; + + foreach ($table->getForeignKeys() as $fkConstraint) { + $options['foreignKeys'][] = $fkConstraint; } } @@ -1578,22 +1340,11 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE $columnData['version'] = $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false; $columnData['comment'] = $this->getColumnComment($column); - if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) { - $columnData['length'] = 255; - } - if (in_array($column->getName(), $options['primary'])) { $columnData['primary'] = true; } - $columns[$columnData['name']] = $columnData; - } - - if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) { - $options['foreignKeys'] = []; - foreach ($table->getForeignKeys() as $fkConstraint) { - $options['foreignKeys'][] = $fkConstraint; - } + $columns[] = $columnData; } if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) { @@ -1621,14 +1372,7 @@ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDE return array_merge($sql, $columnSql); } - /** - * @param string $tableName - * @param string $columnName - * @param string|null $comment - * - * @return string - */ - public function getCommentOnColumnSQL($tableName, $columnName, $comment) + public function getCommentOnColumnSQL(string $tableName, string $columnName, ?string $comment) : string { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); @@ -1644,31 +1388,26 @@ public function getCommentOnColumnSQL($tableName, $columnName, $comment) /** * Returns the SQL to create inline comment on a column. * - * @param string $comment - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getInlineColumnCommentSQL($comment) + public function getInlineColumnCommentSQL(?string $comment) : string { if (! $this->supportsInlineColumnComments()) { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } - return 'COMMENT ' . $this->quoteStringLiteral($comment); + return 'COMMENT ' . $this->quoteStringLiteral((string) $comment); } /** * Returns the SQL used to create a table. * - * @param string $tableName * @param mixed[][] $columns * @param mixed[] $options * - * @return string[] + * @return array */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $columnListSql = $this->getColumnDeclarationListSQL($columns); @@ -1696,7 +1435,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options } $query .= ')'; - $sql[] = $query; + $sql = [$query]; if (isset($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { @@ -1707,10 +1446,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options return $sql; } - /** - * @return string - */ - public function getCreateTemporaryTableSnippetSQL() + public function getCreateTemporaryTableSnippetSQL() : string { return 'CREATE TEMPORARY TABLE'; } @@ -1718,25 +1454,21 @@ public function getCreateTemporaryTableSnippetSQL() /** * Returns the SQL to create a sequence on this platform. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getCreateSequenceSQL(Sequence $sequence) + public function getCreateSequenceSQL(Sequence $sequence) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL to change a sequence on this platform. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getAlterSequenceSQL(Sequence $sequence) + public function getAlterSequenceSQL(Sequence $sequence) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -1744,11 +1476,9 @@ public function getAlterSequenceSQL(Sequence $sequence) * * @param Table|string $table * - * @return string - * * @throws InvalidArgumentException */ - public function getCreateConstraintSQL(Constraint $constraint, $table) + public function getCreateConstraintSQL(Constraint $constraint, $table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -1785,11 +1515,9 @@ public function getCreateConstraintSQL(Constraint $constraint, $table) * * @param Table|string $table The name of the table on which the index is to be created. * - * @return string - * * @throws InvalidArgumentException */ - public function getCreateIndexSQL(Index $index, $table) + public function getCreateIndexSQL(Index $index, $table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -1798,7 +1526,7 @@ public function getCreateIndexSQL(Index $index, $table) $columns = $index->getColumns(); if (count($columns) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + throw new InvalidArgumentException('Incomplete definition. "columns" required.'); } if ($index->isPrimary()) { @@ -1813,10 +1541,8 @@ public function getCreateIndexSQL(Index $index, $table) /** * Adds condition for partial index. - * - * @return string */ - protected function getPartialIndexSQL(Index $index) + protected function getPartialIndexSQL(Index $index) : string { if ($this->supportsPartialIndexes() && $index->hasOption('where')) { return ' WHERE ' . $index->getOption('where'); @@ -1827,10 +1553,8 @@ protected function getPartialIndexSQL(Index $index) /** * Adds additional flags for index generation. - * - * @return string */ - protected function getCreateIndexSQLFlags(Index $index) + protected function getCreateIndexSQLFlags(Index $index) : string { return $index->isUnique() ? 'UNIQUE ' : ''; } @@ -1839,10 +1563,8 @@ protected function getCreateIndexSQLFlags(Index $index) * Returns the SQL to create an unnamed primary key constraint. * * @param Table|string $table - * - * @return string */ - public function getCreatePrimaryKeySQL(Index $index, $table) + public function getCreatePrimaryKeySQL(Index $index, $table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -1854,15 +1576,11 @@ public function getCreatePrimaryKeySQL(Index $index, $table) /** * Returns the SQL to create a named schema. * - * @param string $schemaName - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getCreateSchemaSQL($schemaName) + public function getCreateSchemaSQL(string $schemaName) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -1874,19 +1592,19 @@ public function getCreateSchemaSQL($schemaName) * you SHOULD use them. In general, they end up causing way more * problems than they solve. * - * @param string $str The identifier name to be quoted. + * @param string $identifier The identifier name to be quoted. * * @return string The quoted identifier string. */ - public function quoteIdentifier($str) + public function quoteIdentifier(string $identifier) : string { - if (strpos($str, '.') !== false) { - $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str)); + if (strpos($identifier, '.') !== false) { + $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $identifier)); return implode('.', $parts); } - return $this->quoteSingleIdentifier($str); + return $this->quoteSingleIdentifier($identifier); } /** @@ -1896,7 +1614,7 @@ public function quoteIdentifier($str) * * @return string The quoted identifier string. */ - public function quoteSingleIdentifier($str) + public function quoteSingleIdentifier(string $str) : string { $c = $this->getIdentifierQuoteCharacter(); @@ -1908,10 +1626,8 @@ public function quoteSingleIdentifier($str) * * @param ForeignKeyConstraint $foreignKey The foreign key constraint. * @param Table|string $table The name of the table on which the foreign key is to be created. - * - * @return string */ - public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -1925,21 +1641,19 @@ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) * * This method returns an array of SQL statements, since some platforms need several statements. * - * @return string[] + * @return array * * @throws DBALException If not supported on this platform. */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * @param mixed[] $columnSql - * - * @return bool */ - protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql) + protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, array &$columnSql) : bool { if ($this->_eventManager === null) { return false; @@ -1959,10 +1673,8 @@ protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, /** * @param string[] $columnSql - * - * @return bool */ - protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql) + protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, array &$columnSql) : bool { if ($this->_eventManager === null) { return false; @@ -1982,10 +1694,8 @@ protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $dif /** * @param string[] $columnSql - * - * @return bool */ - protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql) + protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, array &$columnSql) : bool { if ($this->_eventManager === null) { return false; @@ -2004,12 +1714,9 @@ protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableD } /** - * @param string $oldColumnName * @param string[] $columnSql - * - * @return bool */ - protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql) + protected function onSchemaAlterTableRenameColumn(string $oldColumnName, Column $column, TableDiff $diff, array &$columnSql) : bool { if ($this->_eventManager === null) { return false; @@ -2029,10 +1736,8 @@ protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column /** * @param string[] $sql - * - * @return bool */ - protected function onSchemaAlterTable(TableDiff $diff, &$sql) + protected function onSchemaAlterTable(TableDiff $diff, array &$sql) : bool { if ($this->_eventManager === null) { return false; @@ -2053,7 +1758,7 @@ protected function onSchemaAlterTable(TableDiff $diff, &$sql) /** * @return string[] */ - protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) : array { $tableName = $diff->getName($this)->getQuotedName($this); @@ -2080,12 +1785,12 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) /** * @return string[] */ - protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $tableName = $newName->getQuotedName($this); } else { $tableName = $diff->getName($this)->getQuotedName($this); @@ -2129,7 +1834,7 @@ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) * * @return string[] The sequence of SQL statements for renaming the given index. */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { return [ $this->getDropIndexSQL($oldIndexName, $tableName), @@ -2137,22 +1842,12 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) ]; } - /** - * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. - * - * @return string[] - */ - protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) - { - return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff)); - } - /** * Gets declaration of a number of fields in bulk. * - * @param mixed[][] $fields A multidimensional associative array. - * The first dimension determines the field name, while the second - * dimension is keyed with the name of the properties + * @param mixed[][] $fields A multidimensional array. + * The first dimension determines the ordinal position of the field, + * while the second dimension is keyed with the name of the properties * of the field being declared as array indexes. Currently, the types * of supported field properties are as follows: * @@ -2173,15 +1868,13 @@ protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) * Text value with the default COLLATION for this field. * unique * unique constraint - * - * @return string */ - public function getColumnDeclarationListSQL(array $fields) + public function getColumnDeclarationListSQL(array $fields) : string { $queryFields = []; - foreach ($fields as $fieldName => $field) { - $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field); + foreach ($fields as $field) { + $queryFields[] = $this->getColumnDeclarationSQL($field['name'], $field); } return implode(', ', $queryFields); @@ -2220,7 +1913,7 @@ public function getColumnDeclarationListSQL(array $fields) * * @return string DBMS specific SQL code portion that should be used to declare the column. */ - public function getColumnDeclarationSQL($name, array $field) + public function getColumnDeclarationSQL(string $name, array $field) : string { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); @@ -2256,10 +1949,8 @@ public function getColumnDeclarationSQL($name, array $field) * Returns the SQL snippet that declares a floating point column of arbitrary precision. * * @param mixed[] $columnDef - * - * @return string */ - public function getDecimalTypeDeclarationSQL(array $columnDef) + public function getDecimalTypeDeclarationSQL(array $columnDef) : string { $columnDef['precision'] = ! isset($columnDef['precision']) || empty($columnDef['precision']) ? 10 : $columnDef['precision']; @@ -2277,7 +1968,7 @@ public function getDecimalTypeDeclarationSQL(array $columnDef) * * @return string DBMS specific SQL code portion needed to set a default value. */ - public function getDefaultValueDeclarationSQL($field) + public function getDefaultValueDeclarationSQL(array $field) : string { if (! isset($field['default'])) { return empty($field['notnull']) ? ' DEFAULT NULL' : ''; @@ -2311,6 +2002,10 @@ public function getDefaultValueDeclarationSQL($field) return " DEFAULT '" . $this->convertBooleans($default) . "'"; } + if (is_int($default) || is_float($default)) { + return ' DEFAULT ' . $default; + } + return ' DEFAULT ' . $this->quoteStringLiteral($default); } @@ -2322,20 +2017,22 @@ public function getDefaultValueDeclarationSQL($field) * * @return string DBMS specific SQL code portion needed to set a CHECK constraint. */ - public function getCheckDeclarationSQL(array $definition) + public function getCheckDeclarationSQL(array $definition) : string { $constraints = []; - foreach ($definition as $field => $def) { + foreach ($definition as $def) { if (is_string($def)) { $constraints[] = 'CHECK (' . $def . ')'; } else { if (isset($def['min'])) { - $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')'; + $constraints[] = 'CHECK (' . $def['name'] . ' >= ' . $def['min'] . ')'; } - if (isset($def['max'])) { - $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')'; + if (! isset($def['max'])) { + continue; } + + $constraints[] = 'CHECK (' . $def['name'] . ' <= ' . $def['max'] . ')'; } } @@ -2346,25 +2043,36 @@ public function getCheckDeclarationSQL(array $definition) * Obtains DBMS specific SQL code portion needed to set a unique * constraint declaration to be used in statements like CREATE TABLE. * - * @param string $name The name of the unique constraint. - * @param Index $index The index definition. + * @param string $name The name of the unique constraint. + * @param UniqueConstraint $constraint The unique constraint definition. * * @return string DBMS specific SQL code portion needed to set a constraint. * * @throws InvalidArgumentException */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) + public function getUniqueConstraintDeclarationSQL(string $name, UniqueConstraint $constraint) : string { - $columns = $index->getColumns(); - $name = new Identifier($name); + $columns = $constraint->getColumns(); if (count($columns) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + throw new InvalidArgumentException('Incomplete definition. "columns" required.'); } - return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE (' - . $this->getIndexFieldDeclarationListSQL($index) - . ')' . $this->getPartialIndexSQL($index); + $chunks = ['CONSTRAINT']; + + if ($name !== '') { + $chunks[] = (new Identifier($name))->getQuotedName($this); + } + + $chunks[] = 'UNIQUE'; + + if ($constraint->hasFlag('clustered')) { + $chunks[] = 'CLUSTERED'; + } + + $chunks[] = sprintf('(%s)', $this->getIndexFieldDeclarationListSQL($columns)); + + return implode(' ', $chunks); } /** @@ -2378,13 +2086,13 @@ public function getUniqueConstraintDeclarationSQL($name, Index $index) * * @throws InvalidArgumentException */ - public function getIndexDeclarationSQL($name, Index $index) + public function getIndexDeclarationSQL(string $name, Index $index) : string { $columns = $index->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + throw new InvalidArgumentException('Incomplete definition. "columns" required.'); } return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' (' @@ -2398,10 +2106,8 @@ public function getIndexDeclarationSQL($name, Index $index) * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate. * * @param mixed[] $columnDef - * - * @return string */ - public function getCustomTypeDeclarationSQL(array $columnDef) + public function getCustomTypeDeclarationSQL(array $columnDef) : string { return $columnDef['columnDefinition']; } @@ -2449,19 +2155,15 @@ public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string * @return string The string required to be placed between "CREATE" and "TABLE" * to generate a temporary table, if possible. */ - public function getTemporaryTableSQL() + public function getTemporaryTableSQL() : string { return 'TEMPORARY'; } /** * Some vendors require temporary table names to be qualified specially. - * - * @param string $tableName - * - * @return string */ - public function getTemporaryTableName($tableName) + public function getTemporaryTableName(string $tableName) : string { return $tableName; } @@ -2473,7 +2175,7 @@ public function getTemporaryTableName($tableName) * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint * of a field declaration. */ - public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) + public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) : string { $sql = $this->getForeignKeyBaseDeclarationSQL($foreignKey); $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey); @@ -2486,10 +2188,8 @@ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... * * @param ForeignKeyConstraint $foreignKey The foreign key definition. - * - * @return string */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $query = ''; if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) { @@ -2507,11 +2207,9 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey * * @param string $action The foreign key referential action. * - * @return string - * * @throws InvalidArgumentException If unknown referential action given. */ - public function getForeignKeyReferentialActionSQL($action) + public function getForeignKeyReferentialActionSQL(string $action) : string { $upper = strtoupper($action); switch ($upper) { @@ -2522,7 +2220,7 @@ public function getForeignKeyReferentialActionSQL($action) case 'SET DEFAULT': return $upper; default: - throw new InvalidArgumentException('Invalid foreign key action: ' . $upper); + throw new InvalidArgumentException(sprintf('Invalid foreign key action "%s".', $upper)); } } @@ -2530,26 +2228,24 @@ public function getForeignKeyReferentialActionSQL($action) * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint * of a field declaration to be used in statements like CREATE TABLE. * - * @return string - * * @throws InvalidArgumentException */ - public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) + public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) : string { $sql = ''; - if (strlen($foreignKey->getName())) { + if ($foreignKey->getName() !== '') { $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; } $sql .= 'FOREIGN KEY ('; if (count($foreignKey->getLocalColumns()) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'local' required."); + throw new InvalidArgumentException('Incomplete definition. "local" required.'); } if (count($foreignKey->getForeignColumns()) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); + throw new InvalidArgumentException('Incomplete definition. "foreign" required.'); } if (strlen($foreignKey->getForeignTableName()) === 0) { - throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); + throw new InvalidArgumentException('Incomplete definition. "foreignTable" required.'); } return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this)) @@ -2565,7 +2261,7 @@ public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint * of a field declaration. */ - public function getUniqueFieldDeclarationSQL() + public function getUniqueFieldDeclarationSQL() : string { return 'UNIQUE'; } @@ -2579,7 +2275,7 @@ public function getUniqueFieldDeclarationSQL() * @return string DBMS specific SQL code portion needed to set the CHARACTER SET * of a field declaration. */ - public function getColumnCharsetDeclarationSQL($charset) + public function getColumnCharsetDeclarationSQL(string $charset) : string { return ''; } @@ -2593,7 +2289,7 @@ public function getColumnCharsetDeclarationSQL($charset) * @return string DBMS specific SQL code portion needed to set the COLLATION * of a field declaration. */ - public function getColumnCollationDeclarationSQL($collation) + public function getColumnCollationDeclarationSQL(string $collation) : string { return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : ''; } @@ -2601,10 +2297,8 @@ public function getColumnCollationDeclarationSQL($collation) /** * Whether the platform prefers sequences for ID generation. * Subclasses should override this method to return TRUE if they prefer sequences. - * - * @return bool */ - public function prefersSequences() + public function prefersSequences() : bool { return false; } @@ -2612,10 +2306,8 @@ public function prefersSequences() /** * Whether the platform prefers identity columns (eg. autoincrement) for ID generation. * Subclasses should override this method to return TRUE if they prefer identity columns. - * - * @return bool */ - public function prefersIdentityColumns() + public function prefersIdentityColumns() : bool { return false; } @@ -2657,12 +2349,14 @@ public function convertBooleans($item) * The default conversion tries to convert value into bool "(bool)$item" * * @param mixed $item - * - * @return bool|null */ - public function convertFromBoolean($item) + public function convertFromBoolean($item) : ?bool { - return $item === null ? null: (bool) $item; + if ($item === null) { + return null; + } + + return (bool) $item; } /** @@ -2682,30 +2376,24 @@ public function convertBooleansToDatabaseValue($item) /** * Returns the SQL specific for the platform to get the current date. - * - * @return string */ - public function getCurrentDateSQL() + public function getCurrentDateSQL() : string { return 'CURRENT_DATE'; } /** * Returns the SQL specific for the platform to get the current time. - * - * @return string */ - public function getCurrentTimeSQL() + public function getCurrentTimeSQL() : string { return 'CURRENT_TIME'; } /** * Returns the SQL specific for the platform to get the current timestamp - * - * @return string */ - public function getCurrentTimestampSQL() + public function getCurrentTimestampSQL() : string { return 'CURRENT_TIMESTAMP'; } @@ -2713,13 +2401,9 @@ public function getCurrentTimestampSQL() /** * Returns the SQL for a given transaction isolation level Connection constant. * - * @param int $level - * - * @return string - * * @throws InvalidArgumentException */ - protected function _getTransactionIsolationLevelSQL($level) + protected function _getTransactionIsolationLevelSQL(int $level) : string { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: @@ -2731,101 +2415,76 @@ protected function _getTransactionIsolationLevelSQL($level) case TransactionIsolationLevel::SERIALIZABLE: return 'SERIALIZABLE'; default: - throw new InvalidArgumentException('Invalid isolation level:' . $level); + throw new InvalidArgumentException(sprintf('Invalid isolation level "%s".', $level)); } } /** - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListDatabasesSQL() + public function getListDatabasesSQL() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL statement for retrieving the namespaces defined in the database. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListNamespacesSQL() + public function getListNamespacesSQL() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $database - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListSequencesSQL($database) + public function getListSequencesSQL(string $database) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $table - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListTableConstraintsSQL($table) + public function getListTableConstraintsSQL(string $table) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $table - * @param string|null $database - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListTablesSQL() + public function getListTablesSQL() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListUsersSQL() + public function getListUsersSQL() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL to list all views of a database or user. * - * @param string $database - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -2838,53 +2497,35 @@ public function getListViewsSQL($database) * are connected with that database. Cross-database information schema * requests may be impossible. * - * @param string $table - * @param string $currentDatabase - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $table - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getListTableForeignKeysSQL($table) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $name - * @param string $sql - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $name - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -2892,25 +2533,19 @@ public function getDropViewSQL($name) * * @param Sequence|string $sequence * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDropSequenceSQL($sequence) + public function getDropSequenceSQL($sequence) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** - * @param string $sequenceName - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getSequenceNextValSQL($sequenceName) + public function getSequenceNextValSQL(string $sequenceName) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -2918,27 +2553,21 @@ public function getSequenceNextValSQL($sequenceName) * * @param string $database The name of the database that should be created. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getCreateDatabaseSQL($database) + public function getCreateDatabaseSQL(string $database) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Returns the SQL to set the transaction isolation level. * - * @param int $level - * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -2947,23 +2576,19 @@ public function getSetTransactionIsolationSQL($level) * * @param mixed[] $fieldDeclaration * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields. * * @param mixed[] $fieldDeclaration - * - * @return string */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) : string { return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration); } @@ -2974,13 +2599,11 @@ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) * * @param mixed[] $fieldDeclaration * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -2989,21 +2612,17 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) * * @param mixed[] $fieldDeclaration * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * @param mixed[] $fieldDeclaration - * - * @return string */ - public function getFloatDeclarationSQL(array $fieldDeclaration) + public function getFloatDeclarationSQL(array $fieldDeclaration) : string { return 'DOUBLE PRECISION'; } @@ -3015,7 +2634,7 @@ public function getFloatDeclarationSQL(array $fieldDeclaration) * * @return int The default isolation level. */ - public function getDefaultTransactionIsolationLevel() + public function getDefaultTransactionIsolationLevel() : int { return TransactionIsolationLevel::READ_COMMITTED; } @@ -3024,10 +2643,8 @@ public function getDefaultTransactionIsolationLevel() /** * Whether the platform supports sequences. - * - * @return bool */ - public function supportsSequences() + public function supportsSequences() : bool { return false; } @@ -3037,10 +2654,8 @@ public function supportsSequences() * * Identity columns are columns that receive an auto-generated value from the * database on insert of a row. - * - * @return bool */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return false; } @@ -3051,14 +2666,27 @@ public function supportsIdentityColumns() * Some platforms that do not support identity columns natively * but support sequences can emulate identity columns by using * sequences. - * - * @return bool */ - public function usesSequenceEmulatedIdentityColumns() + public function usesSequenceEmulatedIdentityColumns() : bool { return false; } + /** + * Gets the sequence name prefix based on table information. + */ + public function getSequencePrefix(string $tableName, ?string $schemaName = null) : string + { + if (! $schemaName) { + return $tableName; + } + + // Prepend the schema name to the table name if there is one + return ! $this->supportsSchemas() && $this->canEmulateSchemas() + ? $schemaName . '__' . $tableName + : $schemaName . '.' . $tableName; + } + /** * Returns the name of the sequence for a particular identity column in a particular table. * @@ -3067,31 +2695,25 @@ public function usesSequenceEmulatedIdentityColumns() * @param string $tableName The name of the table to return the sequence name for. * @param string $columnName The name of the identity column in the table to return the sequence name for. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getIdentitySequenceName($tableName, $columnName) + public function getIdentitySequenceName(string $tableName, string $columnName) : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Whether the platform supports indexes. - * - * @return bool */ - public function supportsIndexes() + public function supportsIndexes() : bool { return true; } /** * Whether the platform supports partial indexes. - * - * @return bool */ - public function supportsPartialIndexes() + public function supportsPartialIndexes() : bool { return false; } @@ -3106,80 +2728,64 @@ public function supportsColumnLengthIndexes() : bool /** * Whether the platform supports altering tables. - * - * @return bool */ - public function supportsAlterTable() + public function supportsAlterTable() : bool { return true; } /** * Whether the platform supports transactions. - * - * @return bool */ - public function supportsTransactions() + public function supportsTransactions() : bool { return true; } /** * Whether the platform supports savepoints. - * - * @return bool */ - public function supportsSavepoints() + public function supportsSavepoints() : bool { return true; } /** * Whether the platform supports releasing savepoints. - * - * @return bool */ - public function supportsReleaseSavepoints() + public function supportsReleaseSavepoints() : bool { return $this->supportsSavepoints(); } /** * Whether the platform supports primary key constraints. - * - * @return bool */ - public function supportsPrimaryConstraints() + public function supportsPrimaryConstraints() : bool { return true; } /** * Whether the platform supports foreign key constraints. - * - * @return bool */ - public function supportsForeignKeyConstraints() + public function supportsForeignKeyConstraints() : bool { return true; } /** * Whether this platform supports onUpdate in foreign key constraints. - * - * @return bool */ - public function supportsForeignKeyOnUpdate() + public function supportsForeignKeyOnUpdate() : bool { return $this->supportsForeignKeyConstraints(); } /** * Whether the platform supports database schemas. - * - * @return bool */ - public function supportsSchemas() + public function supportsSchemas() : bool { return false; } @@ -3190,10 +2796,8 @@ public function supportsSchemas() * Platforms that either support or emulate schemas don't automatically * filter a schema for the namespaced elements in {@link * AbstractManager#createSchema}. - * - * @return bool */ - public function canEmulateSchemas() + public function canEmulateSchemas() : bool { return false; } @@ -3201,103 +2805,75 @@ public function canEmulateSchemas() /** * Returns the default schema name. * - * @return string - * * @throws DBALException If not supported on this platform. */ - public function getDefaultSchemaName() + public function getDefaultSchemaName() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * Whether this platform supports create database. * * Some databases don't allow to create and drop databases at all or only with certain tools. - * - * @return bool */ - public function supportsCreateDropDatabase() + public function supportsCreateDropDatabase() : bool { return true; } /** * Whether the platform supports getting the affected rows of a recent update/delete type query. - * - * @return bool */ - public function supportsGettingAffectedRows() + public function supportsGettingAffectedRows() : bool { return true; } /** * Whether this platform support to add inline column comments as postfix. - * - * @return bool */ - public function supportsInlineColumnComments() + public function supportsInlineColumnComments() : bool { return false; } /** * Whether this platform support the proprietary syntax "COMMENT ON asset". - * - * @return bool */ - public function supportsCommentOnStatement() + public function supportsCommentOnStatement() : bool { return false; } /** * Does this platform have native guid type. - * - * @return bool */ - public function hasNativeGuidType() + public function hasNativeGuidType() : bool { return false; } /** * Does this platform have native JSON type. - * - * @return bool */ - public function hasNativeJsonType() + public function hasNativeJsonType() : bool { return false; } - /** - * @deprecated - * - * @todo Remove in 3.0 - */ - public function getIdentityColumnNullInsertSQL() - { - return ''; - } - /** * Whether this platform supports views. - * - * @return bool */ - public function supportsViews() + public function supportsViews() : bool { return true; } /** * Does this platform support column collation? - * - * @return bool */ - public function supportsColumnCollation() + public function supportsColumnCollation() : bool { return false; } @@ -3308,7 +2884,7 @@ public function supportsColumnCollation() * * @return string The format string. */ - public function getDateTimeFormatString() + public function getDateTimeFormatString() : string { return 'Y-m-d H:i:s'; } @@ -3319,7 +2895,7 @@ public function getDateTimeFormatString() * * @return string The format string. */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString() : string { return 'Y-m-d H:i:s'; } @@ -3330,7 +2906,7 @@ public function getDateTimeTzFormatString() * * @return string The format string. */ - public function getDateFormatString() + public function getDateFormatString() : string { return 'Y-m-d'; } @@ -3341,7 +2917,7 @@ public function getDateFormatString() * * @return string The format string. */ - public function getTimeFormatString() + public function getTimeFormatString() : string { return 'H:i:s'; } @@ -3349,32 +2925,20 @@ public function getTimeFormatString() /** * Adds an driver-specific LIMIT clause to the query. * - * @param string $query - * @param int|null $limit - * @param int|null $offset - * - * @return string - * * @throws DBALException */ - final public function modifyLimitQuery($query, $limit, $offset = null) + final public function modifyLimitQuery(string $query, ?int $limit, int $offset = 0) : string { - if ($limit !== null) { - $limit = (int) $limit; - } - - $offset = (int) $offset; - if ($offset < 0) { throw new DBALException(sprintf( - 'Offset must be a positive integer or zero, %d given', + 'Offset must be a positive integer or zero, %d given.', $offset )); } if ($offset > 0 && ! $this->supportsLimitOffset()) { throw new DBALException(sprintf( - 'Platform %s does not support offset values in limit queries.', + 'Platform "%s" does not support offset values in limit queries.', $this->getName() )); } @@ -3384,21 +2948,15 @@ final public function modifyLimitQuery($query, $limit, $offset = null) /** * Adds an platform-specific LIMIT clause to the query. - * - * @param string $query - * @param int|null $limit - * @param int|null $offset - * - * @return string */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit !== null) { - $query .= ' LIMIT ' . $limit; + $query .= sprintf(' LIMIT %d', $limit); } if ($offset > 0) { - $query .= ' OFFSET ' . $offset; + $query .= sprintf(' OFFSET %d', $offset); } return $query; @@ -3406,10 +2964,8 @@ protected function doModifyLimitQuery($query, $limit, $offset) /** * Whether the database platform support offsets in modify limit clauses. - * - * @return bool */ - public function supportsLimitOffset() + public function supportsLimitOffset() : bool { return true; } @@ -3421,7 +2977,7 @@ public function supportsLimitOffset() * * @return string The column name in the character casing used in SQL result sets. */ - public function getSQLResultCasing($column) + public function getSQLResultCasing(string $column) : string { return $column; } @@ -3429,35 +2985,24 @@ public function getSQLResultCasing($column) /** * Makes any fixes to a name of a schema element (table, sequence, ...) that are required * by restrictions of the platform, like a maximum length. - * - * @param string $schemaElementName - * - * @return string */ - public function fixSchemaElementName($schemaElementName) + public function fixSchemaElementName(string $schemaElementName) : string { return $schemaElementName; } /** * Maximum length of any given database identifier, like tables or column names. - * - * @return int */ - public function getMaxIdentifierLength() + public function getMaxIdentifierLength() : int { return 63; } /** * Returns the insert SQL for an empty insert statement. - * - * @param string $tableName - * @param string $identifierColumnName - * - * @return string */ - public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) + public function getEmptyIdentityInsertSQL(string $tableName, string $identifierColumnName) : string { return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)'; } @@ -3467,13 +3012,8 @@ public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) * * Cascade is not supported on many platforms but would optionally cascade the truncate by * following the foreign keys. - * - * @param string $tableName - * @param bool $cascade - * - * @return string */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); @@ -3482,48 +3022,32 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * This is for test reasons, many vendors have special requirements for dummy statements. - * - * @return string */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s', $expression); } /** * Returns the SQL to create a new savepoint. - * - * @param string $savepoint - * - * @return string */ - public function createSavePoint($savepoint) + public function createSavePoint(string $savepoint) : string { return 'SAVEPOINT ' . $savepoint; } /** * Returns the SQL to release a savepoint. - * - * @param string $savepoint - * - * @return string */ - public function releaseSavePoint($savepoint) + public function releaseSavePoint(string $savepoint) : string { return 'RELEASE SAVEPOINT ' . $savepoint; } /** * Returns the SQL to rollback a savepoint. - * - * @param string $savepoint - * - * @return string */ - public function rollbackSavePoint($savepoint) + public function rollbackSavePoint(string $savepoint) : string { return 'ROLLBACK TO SAVEPOINT ' . $savepoint; } @@ -3531,11 +3055,9 @@ public function rollbackSavePoint($savepoint) /** * Returns the keyword list instance of this platform. * - * @return KeywordList - * * @throws DBALException If no keyword list is specified. */ - final public function getReservedKeywordsList() + final public function getReservedKeywordsList() : KeywordList { // Check for an existing instantiation of the keywords class. if ($this->_keywords) { @@ -3545,7 +3067,7 @@ final public function getReservedKeywordsList() $class = $this->getReservedKeywordsClass(); $keywords = new $class(); if (! $keywords instanceof KeywordList) { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } // Store the instance so it doesn't need to be generated on every request. @@ -3557,13 +3079,11 @@ final public function getReservedKeywordsList() /** * Returns the class name of the reserved keywords list. * - * @return string - * * @throws DBALException If not supported on this platform. */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** @@ -3576,7 +3096,7 @@ protected function getReservedKeywordsClass() * * @return string The quoted literal string. */ - public function quoteStringLiteral($str) + public function quoteStringLiteral(string $str) : string { $c = $this->getStringLiteralQuoteCharacter(); @@ -3585,10 +3105,8 @@ public function quoteStringLiteral($str) /** * Gets the character used for string literal quoting. - * - * @return string */ - public function getStringLiteralQuoteCharacter() + public function getStringLiteralQuoteCharacter() : string { return "'"; } diff --git a/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/lib/Doctrine/DBAL/Platforms/DB2Platform.php index fcc8c1c67f4..30d001b31c1 100644 --- a/lib/Doctrine/DBAL/Platforms/DB2Platform.php +++ b/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -1,8 +1,10 @@ getCharMaxLength(); - } - - return parent::getVarcharTypeDeclarationSQL($field); - } - /** * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { // todo blob(n) with $field['length']; return 'BLOB(1M)'; @@ -71,31 +34,31 @@ public function getBlobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function initializeDoctrineTypeMappings() + public function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'smallint' => 'smallint', - 'bigint' => 'bigint', - 'integer' => 'integer', - 'time' => 'time', - 'date' => 'date', - 'varchar' => 'string', - 'character' => 'string', - 'varbinary' => 'binary', - 'binary' => 'binary', - 'clob' => 'text', - 'blob' => 'blob', - 'decimal' => 'decimal', - 'double' => 'float', - 'real' => 'float', - 'timestamp' => 'datetime', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'blob' => 'blob', + 'character' => 'string', + 'clob' => 'text', + 'date' => 'date', + 'decimal' => 'decimal', + 'double' => 'float', + 'integer' => 'integer', + 'real' => 'float', + 'smallint' => 'smallint', + 'time' => 'time', + 'timestamp' => 'datetime', + 'varbinary' => 'binary', + 'varchar' => 'string', ]; } /** * {@inheritdoc} */ - public function isCommentedDoctrineType(Type $doctrineType) + public function isCommentedDoctrineType(Type $doctrineType) : bool { if ($doctrineType->getName() === Types::BOOLEAN) { // We require a commented boolean type in order to distinguish between boolean and smallint @@ -109,24 +72,23 @@ public function isCommentedDoctrineType(Type $doctrineType) /** * {@inheritDoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(254)') - : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + return $this->getCharTypeDeclarationSQLSnippet($length) . ' FOR BIT DATA'; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string { - return $this->getVarcharTypeDeclarationSQLSnippet($length, $fixed) . ' FOR BIT DATA'; + return $this->getVarcharTypeDeclarationSQLSnippet($length) . ' FOR BIT DATA'; } /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { // todo clob(n) with $field['length']; return 'CLOB(1M)'; @@ -135,7 +97,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'db2'; } @@ -143,7 +105,7 @@ public function getName() /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $columnDef) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'SMALLINT'; } @@ -151,7 +113,7 @@ public function getBooleanTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $columnDef) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } @@ -159,7 +121,7 @@ public function getIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $columnDef) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } @@ -167,7 +129,7 @@ public function getBigIntTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $columnDef) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } @@ -175,7 +137,7 @@ public function getSmallIntTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { $autoinc = ''; if (! empty($columnDef['autoincrement'])) { @@ -188,7 +150,7 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - public function getBitAndComparisonExpression($value1, $value2) + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } @@ -196,7 +158,7 @@ public function getBitAndComparisonExpression($value1, $value2) /** * {@inheritdoc} */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return 'BITOR(' . $value1 . ', ' . $value2 . ')'; } @@ -204,17 +166,17 @@ public function getBitOrComparisonExpression($value1, $value2) /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { switch ($unit) { case DateIntervalUnit::WEEK: - $interval *= 7; - $unit = DateIntervalUnit::DAY; + $interval = $this->multiplyInterval($interval, 7); + $unit = DateIntervalUnit::DAY; break; case DateIntervalUnit::QUARTER: - $interval *= 3; - $unit = DateIntervalUnit::MONTH; + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; break; } @@ -224,7 +186,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritdoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')'; } @@ -232,7 +194,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { return 'TIMESTAMP(0) WITH DEFAULT'; @@ -244,7 +206,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -252,7 +214,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIME'; } @@ -260,7 +222,7 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritdoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); @@ -269,13 +231,8 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * This code fragment is originally from the Zend_Db_Adapter_Db2 class, but has been edited. - * - * @param string $table - * @param string $database - * - * @return string */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { $table = $this->quoteStringLiteral($table); @@ -326,7 +283,7 @@ public function getListTableColumnsSQL($table, $database = null) /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'"; } @@ -334,7 +291,7 @@ public function getListTablesSQL() /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return 'SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS'; } @@ -342,7 +299,7 @@ public function getListViewsSQL($database) /** * {@inheritDoc} */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { $table = $this->quoteStringLiteral($table); @@ -366,7 +323,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { $table = $this->quoteStringLiteral($table); @@ -400,7 +357,7 @@ public function getListTableForeignKeysSQL($table) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -408,7 +365,7 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } @@ -416,7 +373,7 @@ public function getDropViewSQL($name) /** * {@inheritDoc} */ - public function getCreateDatabaseSQL($database) + public function getCreateDatabaseSQL(string $database) : string { return 'CREATE DATABASE ' . $database; } @@ -424,7 +381,7 @@ public function getCreateDatabaseSQL($database) /** * {@inheritDoc} */ - public function getDropDatabaseSQL($database) + public function getDropDatabaseSQL(string $database) : string { return 'DROP DATABASE ' . $database; } @@ -432,7 +389,7 @@ public function getDropDatabaseSQL($database) /** * {@inheritDoc} */ - public function supportsCreateDropDatabase() + public function supportsCreateDropDatabase() : bool { return false; } @@ -440,7 +397,7 @@ public function supportsCreateDropDatabase() /** * {@inheritDoc} */ - public function supportsReleaseSavepoints() + public function supportsReleaseSavepoints() : bool { return false; } @@ -448,7 +405,7 @@ public function supportsReleaseSavepoints() /** * {@inheritdoc} */ - public function supportsCommentOnStatement() + public function supportsCommentOnStatement() : bool { return true; } @@ -456,7 +413,7 @@ public function supportsCommentOnStatement() /** * {@inheritDoc} */ - public function getCurrentDateSQL() + public function getCurrentDateSQL() : string { return 'CURRENT DATE'; } @@ -464,7 +421,7 @@ public function getCurrentDateSQL() /** * {@inheritDoc} */ - public function getCurrentTimeSQL() + public function getCurrentTimeSQL() : string { return 'CURRENT TIME'; } @@ -472,7 +429,7 @@ public function getCurrentTimeSQL() /** * {@inheritDoc} */ - public function getCurrentTimestampSQL() + public function getCurrentTimestampSQL() : string { return 'CURRENT TIMESTAMP'; } @@ -480,16 +437,16 @@ public function getCurrentTimestampSQL() /** * {@inheritDoc} */ - public function getIndexDeclarationSQL($name, Index $index) + public function getIndexDeclarationSQL(string $name, Index $index) : string { // Index declaration in statements like CREATE TABLE is not supported. - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * {@inheritDoc} */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $indexes = []; if (isset($options['indexes'])) { @@ -509,7 +466,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $sql = []; $columnSql = []; @@ -602,7 +559,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = sprintf( 'RENAME TABLE %s TO %s', $diff->getName($this)->getQuotedName($this), @@ -628,7 +585,7 @@ public function getAlterTableSQL(TableDiff $diff) * @param string[] $sql The sequence of table alteration statements to fill. * @param mixed[] $queryParts The sequence of column alteration clauses to fill. */ - private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts) + private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts) : void { $alterColumnClauses = $this->getAlterColumnClausesSQL($columnDiff); @@ -658,7 +615,7 @@ private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, * * @return string[] */ - private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) + private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) : array { $column = $columnDiff->column->toArray(); @@ -701,7 +658,7 @@ private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) /** * {@inheritDoc} */ - protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $table = $diff->getName($this)->getQuotedName($this); @@ -734,7 +691,7 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) /** * {@inheritdoc} */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); @@ -747,7 +704,7 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) /** * {@inheritDoc} */ - public function getDefaultValueDeclarationSQL($field) + public function getDefaultValueDeclarationSQL(array $field) : string { if (! empty($field['autoincrement'])) { return ''; @@ -765,7 +722,7 @@ public function getDefaultValueDeclarationSQL($field) /** * {@inheritDoc} */ - public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) + public function getEmptyIdentityInsertSQL(string $tableName, string $identifierColumnName) : string { return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)'; } @@ -773,7 +730,7 @@ public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) /** * {@inheritDoc} */ - public function getCreateTemporaryTableSnippetSQL() + public function getCreateTemporaryTableSnippetSQL() : string { return 'DECLARE GLOBAL TEMPORARY TABLE'; } @@ -781,7 +738,7 @@ public function getCreateTemporaryTableSnippetSQL() /** * {@inheritDoc} */ - public function getTemporaryTableName($tableName) + public function getTemporaryTableName(string $tableName) : string { return 'SESSION.' . $tableName; } @@ -789,7 +746,7 @@ public function getTemporaryTableName($tableName) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $where = []; @@ -816,31 +773,31 @@ protected function doModifyLimitQuery($query, $limit, $offset = null) /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $substr . ', ' . $str . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $substring, $string); } - return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $substring, $string, $start); } /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTR(' . $value . ', ' . $from . ')'; + return sprintf('SUBSTR(%s, %s)', $string, $start); } - return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')'; + return sprintf('SUBSTR(%s, %s, %s)', $string, $start, $length); } /** * {@inheritDoc} */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return true; } @@ -848,7 +805,7 @@ public function supportsIdentityColumns() /** * {@inheritDoc} */ - public function prefersIdentityColumns() + public function prefersIdentityColumns() : bool { return true; } @@ -858,7 +815,7 @@ public function prefersIdentityColumns() * * DB2 returns all column names in SQL result sets in uppercase. */ - public function getSQLResultCasing($column) + public function getSQLResultCasing(string $column) : string { return strtoupper($column); } @@ -866,7 +823,7 @@ public function getSQLResultCasing($column) /** * {@inheritDoc} */ - public function getForUpdateSQL() + public function getForUpdateSQL() : string { return ' WITH RR USE AND KEEP UPDATE LOCKS'; } @@ -874,10 +831,8 @@ public function getForUpdateSQL() /** * {@inheritDoc} */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s FROM sysibm.sysdummy1', $expression); } @@ -888,7 +843,7 @@ public function getDummySelectSQL() * * TODO: We have to investigate how to get DB2 up and running with savepoints. */ - public function supportsSavepoints() + public function supportsSavepoints() : bool { return false; } @@ -896,7 +851,7 @@ public function supportsSavepoints() /** * {@inheritDoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\DB2Keywords::class; } diff --git a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php b/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php deleted file mode 100644 index 8f6f0966323..00000000000 --- a/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php +++ /dev/null @@ -1,621 +0,0 @@ -_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) - { - $autoinc = ''; - if (! empty($columnDef['autoincrement'])) { - $autoinc = ' AUTO_INCREMENT'; - } - - return $autoinc; - } - - /** - * {@inheritDoc} - */ - public function getBigIntTypeDeclarationSQL(array $field) - { - return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - public function getSmallIntTypeDeclarationSQL(array $field) - { - return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); - } - - /** - * {@inheritDoc} - */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) - { - return $length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'; - } - - /** - * {@inheritdoc} - */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) - { - return 'VARBINARY(' . ($length ?: 255) . ')'; - } - - /** - * {@inheritDoc} - */ - protected function initializeDoctrineTypeMappings() - { - $this->doctrineTypeMapping = [ - 'boolean' => 'boolean', - 'varchar' => 'string', - 'varbinary' => 'binary', - 'integer' => 'integer', - 'blob' => 'blob', - 'decimal' => 'decimal', - 'datetime' => 'datetime', - 'date' => 'date', - 'time' => 'time', - 'text' => 'text', - 'timestamp' => 'datetime', - 'double' => 'float', - 'bigint' => 'bigint', - ]; - } - - /** - * {@inheritDoc} - */ - public function getClobTypeDeclarationSQL(array $field) - { - return 'TEXT'; - } - - /** - * {@inheritDoc} - */ - public function getBlobTypeDeclarationSQL(array $field) - { - return 'BLOB'; - } - - /** - * {@inheritDoc} - */ - public function getCreateDatabaseSQL($name) - { - return 'CREATE DATABASE ' . $name; - } - - /** - * {@inheritDoc} - */ - public function getDropDatabaseSQL($name) - { - return 'DROP DATABASE ' . $name; - } - - /** - * {@inheritDoc} - */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) - { - $queryFields = $this->getColumnDeclarationListSQL($columns); - - if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { - foreach ($options['uniqueConstraints'] as $index => $definition) { - $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); - } - } - - // add all indexes - if (isset($options['indexes']) && ! empty($options['indexes'])) { - foreach ($options['indexes'] as $index => $definition) { - $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); - } - } - - // attach all primary keys - if (isset($options['primary']) && ! empty($options['primary'])) { - $keyColumns = array_unique(array_values($options['primary'])); - $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; - } - - $query = 'CREATE '; - - if (! empty($options['temporary'])) { - $query .= 'TEMPORARY '; - } - - $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; - $query .= $this->buildTableOptions($options); - $query .= $this->buildPartitionOptions($options); - - $sql = [$query]; - - if (isset($options['foreignKeys'])) { - foreach ((array) $options['foreignKeys'] as $definition) { - $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); - } - } - - return $sql; - } - - /** - * Build SQL for table options - * - * @param mixed[] $options - * - * @return string - */ - private function buildTableOptions(array $options) - { - if (isset($options['table_options'])) { - return $options['table_options']; - } - - $tableOptions = []; - - // Collate - if (! isset($options['collate'])) { - $options['collate'] = 'utf8_unicode_ci'; - } - - $tableOptions[] = sprintf('COLLATE %s', $options['collate']); - - // Engine - if (! isset($options['engine'])) { - $options['engine'] = 'InnoDB'; - } - - $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); - - // Auto increment - if (isset($options['auto_increment'])) { - $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); - } - - // Comment - if (isset($options['comment'])) { - $comment = trim($options['comment'], " '"); - - $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($comment)); - } - - // Row format - if (isset($options['row_format'])) { - $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); - } - - return implode(' ', $tableOptions); - } - - /** - * Build SQL for partition options. - * - * @param mixed[] $options - * - * @return string - */ - private function buildPartitionOptions(array $options) - { - return isset($options['partition_options']) - ? ' ' . $options['partition_options'] - : ''; - } - - /** - * {@inheritDoc} - */ - public function getListDatabasesSQL() - { - return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'"; - } - - /** - * {@inheritDoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\DrizzleKeywords::class; - } - - /** - * {@inheritDoc} - */ - public function getListTablesSQL() - { - return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE' AND TABLE_SCHEMA=DATABASE()"; - } - - /** - * {@inheritDoc} - */ - public function getListTableColumnsSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return 'SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT,' . - ' NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME' . - ' FROM DATA_DICTIONARY.COLUMNS' . - ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME = ' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function getListTableForeignKeysSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return 'SELECT CONSTRAINT_NAME, CONSTRAINT_COLUMNS, REFERENCED_TABLE_NAME, REFERENCED_TABLE_COLUMNS, UPDATE_RULE, DELETE_RULE' . - ' FROM DATA_DICTIONARY.FOREIGN_KEYS' . - ' WHERE CONSTRAINT_SCHEMA=' . $databaseSQL . ' AND CONSTRAINT_TABLE=' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function getListTableIndexesSQL($table, $database = null) - { - if ($database) { - $databaseSQL = $this->quoteStringLiteral($database); - } else { - $databaseSQL = 'DATABASE()'; - } - - return "SELECT INDEX_NAME AS 'key_name', COLUMN_NAME AS 'column_name', IS_USED_IN_PRIMARY AS 'primary', IS_UNIQUE=0 AS 'non_unique'" . - ' FROM DATA_DICTIONARY.INDEX_PARTS' . - ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME=' . $this->quoteStringLiteral($table); - } - - /** - * {@inheritDoc} - */ - public function prefersIdentityColumns() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsIdentityColumns() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsInlineColumnComments() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function supportsViews() - { - return false; - } - - /** - * {@inheritdoc} - */ - public function supportsColumnCollation() - { - return true; - } - - /** - * {@inheritDoc} - */ - public function getDropIndexSQL($index, $table = null) - { - if ($index instanceof Index) { - $indexName = $index->getQuotedName($this); - } elseif (is_string($index)) { - $indexName = $index; - } else { - throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); - } - - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } elseif (! is_string($table)) { - throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } - - if ($index instanceof Index && $index->isPrimary()) { - // drizzle primary keys are always named "PRIMARY", - // so we cannot use them in statements because of them being keyword. - return $this->getDropPrimaryKeySQL($table); - } - - return 'DROP INDEX ' . $indexName . ' ON ' . $table; - } - - /** - * {@inheritDoc} - */ - protected function getDropPrimaryKeySQL($table) - { - return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; - } - - /** - * {@inheritDoc} - */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) - { - if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { - return 'TIMESTAMP'; - } - - return 'DATETIME'; - } - - /** - * {@inheritDoc} - */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) - { - return 'TIME'; - } - - /** - * {@inheritDoc} - */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) - { - return 'DATE'; - } - - /** - * {@inheritDoc} - */ - public function getAlterTableSQL(TableDiff $diff) - { - $columnSql = []; - $queryParts = []; - - $newName = $diff->getNewName(); - - if ($newName !== false) { - $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); - } - - foreach ($diff->addedColumns as $column) { - if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { - continue; - } - - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - foreach ($diff->removedColumns as $column) { - if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { - continue; - } - - $queryParts[] = 'DROP ' . $column->getQuotedName($this); - } - - foreach ($diff->changedColumns as $columnDiff) { - if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { - continue; - } - - $column = $columnDiff->column; - $columnArray = $column->toArray(); - - // Do not generate column alteration clause if type is binary and only fixed property has changed. - // Drizzle only supports binary type columns with variable length. - // Avoids unnecessary table alteration statements. - if ($columnArray['type'] instanceof BinaryType && - $columnDiff->hasChanged('fixed') && - count($columnDiff->changedProperties) === 1 - ) { - continue; - } - - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - foreach ($diff->renamedColumns as $oldColumnName => $column) { - if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { - continue; - } - - $oldColumnName = new Identifier($oldColumnName); - - $columnArray = $column->toArray(); - $columnArray['comment'] = $this->getColumnComment($column); - $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' - . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); - } - - $sql = []; - $tableSql = []; - - if (! $this->onSchemaAlterTable($diff, $tableSql)) { - if (count($queryParts) > 0) { - $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(', ', $queryParts); - } - $sql = array_merge( - $this->getPreAlterTableIndexForeignKeySQL($diff), - $sql, - $this->getPostAlterTableIndexForeignKeySQL($diff) - ); - } - - return array_merge($sql, $tableSql, $columnSql); - } - - /** - * {@inheritDoc} - */ - public function getDropTemporaryTableSQL($table) - { - if ($table instanceof Table) { - $table = $table->getQuotedName($this); - } elseif (! is_string($table)) { - throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); - } - - return 'DROP TEMPORARY TABLE ' . $table; - } - - /** - * {@inheritDoc} - */ - public function convertBooleans($item) - { - if (is_array($item)) { - foreach ($item as $key => $value) { - if (! is_bool($value) && ! is_numeric($value)) { - continue; - } - - $item[$key] = $value ? 'true' : 'false'; - } - } elseif (is_bool($item) || is_numeric($item)) { - $item = $item ? 'true' : 'false'; - } - - return $item; - } - - /** - * {@inheritDoc} - */ - public function getLocateExpression($str, $substr, $startPos = false) - { - if ($startPos === false) { - return 'LOCATE(' . $substr . ', ' . $str . ')'; - } - - return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; - } - - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'UUID()'; - } - - /** - * {@inheritDoc} - */ - public function getRegexpExpression() - { - return 'RLIKE'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/Exception/InvalidPlatformVersion.php b/lib/Doctrine/DBAL/Platforms/Exception/InvalidPlatformVersion.php new file mode 100644 index 00000000000..34874301301 --- /dev/null +++ b/lib/Doctrine/DBAL/Platforms/Exception/InvalidPlatformVersion.php @@ -0,0 +1,28 @@ +keywords === null) { $this->initializeKeywords(); @@ -30,10 +28,7 @@ public function isKeyword($word) return isset($this->keywords[strtoupper($word)]); } - /** - * @return void - */ - protected function initializeKeywords() + protected function initializeKeywords() : void { $this->keywords = array_flip(array_map('strtoupper', $this->getKeywords())); } @@ -43,12 +38,10 @@ protected function initializeKeywords() * * @return string[] */ - abstract protected function getKeywords(); + abstract protected function getKeywords() : array; /** * Returns the name of this keyword list. - * - * @return string */ - abstract public function getName(); + abstract public function getName() : string; } diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php index 1b31c7682e7..010f694232a 100644 --- a/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php +++ b/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php @@ -1,5 +1,7 @@ violations; } /** - * @param string $word - * * @return string[] */ - private function isReservedWord($word) + private function isReservedWord(string $word) : array { if ($word[0] === '`') { $word = str_replace('`', '', $word); @@ -60,12 +60,9 @@ private function isReservedWord($word) } /** - * @param string $asset * @param string[] $violatedPlatforms - * - * @return void */ - private function addViolation($asset, $violatedPlatforms) + private function addViolation(string $asset, array $violatedPlatforms) : void { if (! $violatedPlatforms) { return; @@ -77,7 +74,7 @@ private function addViolation($asset, $violatedPlatforms) /** * {@inheritdoc} */ - public function acceptColumn(Table $table, Column $column) + public function acceptColumn(Table $table, Column $column) : void { $this->addViolation( 'Table ' . $table->getName() . ' column ' . $column->getName(), @@ -88,35 +85,35 @@ public function acceptColumn(Table $table, Column $column) /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { } /** * {@inheritdoc} */ - public function acceptIndex(Table $table, Index $index) + public function acceptIndex(Table $table, Index $index) : void { } /** * {@inheritdoc} */ - public function acceptSchema(Schema $schema) + public function acceptSchema(Schema $schema) : void { } /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { } /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { $this->addViolation( 'Table ' . $table->getName(), diff --git a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php b/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php deleted file mode 100644 index 09513c5770e..00000000000 --- a/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php +++ /dev/null @@ -1,39 +0,0 @@ -getQuotedName($this)]; } @@ -54,7 +56,7 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) /** * {@inheritdoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\MySQL57Keywords::class; } @@ -62,7 +64,7 @@ protected function getReservedKeywordsClass() /** * {@inheritdoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { parent::initializeDoctrineTypeMappings(); diff --git a/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php b/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php index f6d4be9dc4c..cdf8428628f 100644 --- a/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php +++ b/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php @@ -1,5 +1,7 @@ quoteStringLiteral($currentDatabase); @@ -167,24 +158,18 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { - $database = $this->quoteStringLiteral($database); - - return 'SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ' . $database; + return 'SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ' . $this->quoteStringLiteral($database); } /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table, $database = null) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { $table = $this->quoteStringLiteral($table); - if ($database !== null) { - $database = $this->quoteStringLiteral($database); - } - $sql = 'SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ' . 'k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ' . 'FROM information_schema.key_column_usage k /*!50116 ' . @@ -192,7 +177,7 @@ public function getListTableForeignKeysSQL($table, $database = null) ' c.constraint_name = k.constraint_name AND ' . ' c.table_name = ' . $table . ' */ WHERE k.table_name = ' . $table; - $databaseNameSql = $database ?? 'DATABASE()'; + $databaseNameSql = $this->getDatabaseNameSql($database); $sql .= ' AND k.table_schema = ' . $databaseNameSql . ' /*!50116 AND c.constraint_schema = ' . $databaseNameSql . ' */'; $sql .= ' AND k.`REFERENCED_COLUMN_NAME` is not NULL'; @@ -203,7 +188,7 @@ public function getListTableForeignKeysSQL($table, $database = null) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -211,28 +196,11 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } - /** - * {@inheritDoc} - */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) - { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') - : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); - } - - /** - * {@inheritdoc} - */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) - { - return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; - } - /** * Gets the SQL snippet used to declare a CLOB column type. * TINYTEXT : 2 ^ 8 - 1 = 255 @@ -242,7 +210,7 @@ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) * * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { if (! empty($field['length']) && is_numeric($field['length'])) { $length = $field['length']; @@ -266,7 +234,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { return 'TIMESTAMP'; @@ -278,7 +246,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -286,7 +254,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIME'; } @@ -294,34 +262,18 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'TINYINT(1)'; } - /** - * Obtain DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration to be used in statements like CREATE TABLE. - * - * @deprecated Deprecated since version 2.5, Use {@link self::getColumnCollationDeclarationSQL()} instead. - * - * @param string $collation name of the collation - * - * @return string DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration. - */ - public function getCollationFieldDeclaration($collation) - { - return $this->getColumnCollationDeclarationSQL($collation); - } - /** * {@inheritDoc} * * MySql prefers "autoincrement" identity columns since sequences can only * be emulated with a table. */ - public function prefersIdentityColumns() + public function prefersIdentityColumns() : bool { return true; } @@ -331,7 +283,7 @@ public function prefersIdentityColumns() * * MySql supports this through AUTO_INCREMENT columns. */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return true; } @@ -339,7 +291,7 @@ public function supportsIdentityColumns() /** * {@inheritDoc} */ - public function supportsInlineColumnComments() + public function supportsInlineColumnComments() : bool { return true; } @@ -347,7 +299,7 @@ public function supportsInlineColumnComments() /** * {@inheritDoc} */ - public function supportsColumnCollation() + public function supportsColumnCollation() : bool { return true; } @@ -355,7 +307,7 @@ public function supportsColumnCollation() /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"; } @@ -363,21 +315,13 @@ public function getListTablesSQL() /** * {@inheritDoc} */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { - $table = $this->quoteStringLiteral($table); - - if ($database) { - $database = $this->quoteStringLiteral($database); - } else { - $database = 'DATABASE()'; - } - return 'SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ' . 'COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, ' . 'CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS Collation ' . - 'FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ' . $database . ' AND TABLE_NAME = ' . $table . - ' ORDER BY ORDINAL_POSITION ASC'; + 'FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ' . $this->getDatabaseNameSql($database) . ' ' . + 'AND TABLE_NAME = ' . $this->quoteStringLiteral($table) . ' ORDER BY ORDINAL_POSITION'; } public function getListTableMetadataSQL(string $table, ?string $database = null) : string @@ -397,29 +341,29 @@ public function getListTableMetadataSQL(string $table, ?string $database = null) /** * {@inheritDoc} */ - public function getCreateDatabaseSQL($name) + public function getCreateDatabaseSQL(string $database) : string { - return 'CREATE DATABASE ' . $name; + return 'CREATE DATABASE ' . $database; } /** * {@inheritDoc} */ - public function getDropDatabaseSQL($name) + public function getDropDatabaseSQL(string $database) : string { - return 'DROP DATABASE ' . $name; + return 'DROP DATABASE ' . $database; } /** * {@inheritDoc} */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { - foreach ($options['uniqueConstraints'] as $index => $definition) { - $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); + foreach ($options['uniqueConstraints'] as $name => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } @@ -466,7 +410,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options /** * {@inheritdoc} */ - public function getDefaultValueDeclarationSQL($field) + public function getDefaultValueDeclarationSQL(array $field) : string { // Unset the default value if the given field definition does not allow default values. if ($field['type'] instanceof TextType || $field['type'] instanceof BlobType) { @@ -480,10 +424,8 @@ public function getDefaultValueDeclarationSQL($field) * Build SQL for table options * * @param mixed[] $options - * - * @return string */ - private function buildTableOptions(array $options) + private function buildTableOptions(array $options) : string { if (isset($options['table_options'])) { return $options['table_options']; @@ -536,10 +478,8 @@ private function buildTableOptions(array $options) * Build SQL for partition options. * * @param mixed[] $options - * - * @return string */ - private function buildPartitionOptions(array $options) + private function buildPartitionOptions(array $options) : string { return isset($options['partition_options']) ? ' ' . $options['partition_options'] @@ -549,13 +489,13 @@ private function buildPartitionOptions(array $options) /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $columnSql = []; $queryParts = []; $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); } @@ -647,7 +587,7 @@ public function getAlterTableSQL(TableDiff $diff) /** * {@inheritDoc} */ - protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $table = $diff->getName($this)->getQuotedName($this); @@ -708,7 +648,7 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) /** * @return string[] */ - private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $index) + private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $index) : array { $sql = []; @@ -726,7 +666,7 @@ private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $inde $column = $diff->fromTable->getColumn($columnName); - if ($column->getAutoincrement() !== true) { + if (! $column->getAutoincrement()) { continue; } @@ -747,7 +687,7 @@ private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $inde * * @return string[] */ - private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) + private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $table = $diff->getName($this)->getQuotedName($this); @@ -787,7 +727,7 @@ private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) * * @return string[] */ - protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $tableName = $diff->getName($this)->getQuotedName($this); @@ -813,7 +753,7 @@ protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) * * @return ForeignKeyConstraint[] */ - private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableDiff $diff) + private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableDiff $diff) : array { if (empty($diff->renamedIndexes) || ! $diff->fromTable instanceof Table) { return []; @@ -842,7 +782,7 @@ private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableD /** * {@inheritdoc} */ - protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) : array { return array_merge( parent::getPostAlterTableIndexForeignKeySQL($diff), @@ -855,12 +795,12 @@ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) * * @return string[] */ - protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) + protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) : array { $sql = []; $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $tableName = $newName->getQuotedName($this); } else { $tableName = $diff->getName($this)->getQuotedName($this); @@ -880,7 +820,7 @@ protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) /** * {@inheritDoc} */ - protected function getCreateIndexSQLFlags(Index $index) + protected function getCreateIndexSQLFlags(Index $index) : string { $type = ''; if ($index->isUnique()) { @@ -897,39 +837,39 @@ protected function getCreateIndexSQLFlags(Index $index) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { - return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { - return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { - return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritdoc} */ - public function getFloatDeclarationSQL(array $field) + public function getFloatDeclarationSQL(array $fieldDeclaration) : string { - return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($field); + return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($fieldDeclaration); } /** * {@inheritdoc} */ - public function getDecimalTypeDeclarationSQL(array $columnDef) + public function getDecimalTypeDeclarationSQL(array $columnDef) : string { return parent::getDecimalTypeDeclarationSQL($columnDef) . $this->getUnsignedDeclaration($columnDef); } @@ -938,10 +878,8 @@ public function getDecimalTypeDeclarationSQL(array $columnDef) * Get unsigned declaration for a column. * * @param mixed[] $columnDef - * - * @return string */ - private function getUnsignedDeclaration(array $columnDef) + private function getUnsignedDeclaration(array $columnDef) : string { return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : ''; } @@ -949,7 +887,7 @@ private function getUnsignedDeclaration(array $columnDef) /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { $autoinc = ''; if (! empty($columnDef['autoincrement'])) { @@ -962,7 +900,7 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getColumnCharsetDeclarationSQL($charset) + public function getColumnCharsetDeclarationSQL(string $charset) : string { return 'CHARACTER SET ' . $charset; } @@ -970,7 +908,7 @@ public function getColumnCharsetDeclarationSQL($charset) /** * {@inheritDoc} */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $query = ''; if ($foreignKey->hasOption('match')) { @@ -984,7 +922,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey /** * {@inheritDoc} */ - public function getDropIndexSQL($index, $table = null) + public function getDropIndexSQL($index, $table = null) : string { if ($index instanceof Index) { $indexName = $index->getQuotedName($this); @@ -1009,12 +947,7 @@ public function getDropIndexSQL($index, $table = null) return 'DROP INDEX ' . $indexName . ' ON ' . $table; } - /** - * @param string $table - * - * @return string - */ - protected function getDropPrimaryKeySQL($table) + protected function getDropPrimaryKeySQL(string $table) : string { return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; } @@ -1022,7 +955,7 @@ protected function getDropPrimaryKeySQL($table) /** * {@inheritDoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } @@ -1030,7 +963,7 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'mysql'; } @@ -1038,7 +971,7 @@ public function getName() /** * {@inheritDoc} */ - public function getReadLockSQL() + public function getReadLockSQL() : string { return 'LOCK IN SHARE MODE'; } @@ -1046,62 +979,46 @@ public function getReadLockSQL() /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'tinyint' => 'boolean', - 'smallint' => 'smallint', - 'mediumint' => 'integer', - 'int' => 'integer', - 'integer' => 'integer', - 'bigint' => 'bigint', - 'tinytext' => 'text', - 'mediumtext' => 'text', - 'longtext' => 'text', - 'text' => 'text', - 'varchar' => 'string', - 'string' => 'string', - 'char' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'time' => 'time', - 'float' => 'float', - 'double' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', - 'numeric' => 'decimal', - 'year' => 'date', - 'longblob' => 'blob', - 'blob' => 'blob', - 'mediumblob' => 'blob', - 'tinyblob' => 'blob', - 'binary' => 'binary', - 'varbinary' => 'binary', - 'set' => 'simple_array', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'blob' => 'blob', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'decimal' => 'decimal', + 'double' => 'float', + 'float' => 'float', + 'int' => 'integer', + 'integer' => 'integer', + 'longblob' => 'blob', + 'longtext' => 'text', + 'mediumblob' => 'blob', + 'mediumint' => 'integer', + 'mediumtext' => 'text', + 'numeric' => 'decimal', + 'real' => 'float', + 'set' => 'simple_array', + 'smallint' => 'smallint', + 'string' => 'string', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'tinyblob' => 'blob', + 'tinyint' => 'boolean', + 'tinytext' => 'text', + 'varbinary' => 'binary', + 'varchar' => 'string', + 'year' => 'date', ]; } /** * {@inheritDoc} */ - public function getVarcharMaxLength() - { - return 65535; - } - - /** - * {@inheritdoc} - */ - public function getBinaryMaxLength() - { - return 65535; - } - - /** - * {@inheritDoc} - */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\MySQLKeywords::class; } @@ -1112,7 +1029,7 @@ protected function getReservedKeywordsClass() * MySQL commits a transaction implicitly when DROP TABLE is executed, however not * if DROP TEMPORARY TABLE is executed. */ - public function getDropTemporaryTableSQL($table) + public function getDropTemporaryTableSQL($table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -1132,7 +1049,7 @@ public function getDropTemporaryTableSQL($table) * * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { if (! empty($field['length']) && is_numeric($field['length'])) { $length = $field['length']; @@ -1156,7 +1073,7 @@ public function getBlobTypeDeclarationSQL(array $field) /** * {@inheritdoc} */ - public function quoteStringLiteral($str) + public function quoteStringLiteral(string $str) : string { $str = str_replace('\\', '\\\\', $str); // MySQL requires backslashes to be escaped aswell. @@ -1166,7 +1083,7 @@ public function quoteStringLiteral($str) /** * {@inheritdoc} */ - public function getDefaultTransactionIsolationLevel() + public function getDefaultTransactionIsolationLevel() : int { return TransactionIsolationLevel::REPEATABLE_READ; } @@ -1178,4 +1095,18 @@ public function supportsColumnLengthIndexes() : bool { return true; } + + /** + * Returns an SQL expression representing the given database name or current database name + * + * @param string|null $database Database name + */ + private function getDatabaseNameSql(?string $database) : string + { + if ($database === null) { + return 'DATABASE()'; + } + + return $this->quoteStringLiteral($database); + } } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index ced7fbf9bdc..b520c3ea370 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -1,8 +1,11 @@ multiplyInterval($interval, 3); break; case DateIntervalUnit::YEAR: - $interval *= 12; + $interval = $this->multiplyInterval($interval, 12); break; } @@ -143,7 +132,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return sprintf('TRUNC(%s) - TRUNC(%s)', $date1, $date2); } @@ -151,7 +140,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - public function getBitAndComparisonExpression($value1, $value2) + public function getBitAndComparisonExpression(string $value1, string $value2) : string { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } @@ -159,7 +148,7 @@ public function getBitAndComparisonExpression($value1, $value2) /** * {@inheritDoc} */ - public function getBitOrComparisonExpression($value1, $value2) + public function getBitOrComparisonExpression(string $value1, string $value2) : string { return '(' . $value1 . '-' . $this->getBitAndComparisonExpression($value1, $value2) @@ -173,7 +162,7 @@ public function getBitOrComparisonExpression($value1, $value2) * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection * in {@see listSequences()} */ - public function getCreateSequenceSQL(Sequence $sequence) + public function getCreateSequenceSQL(Sequence $sequence) : string { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' START WITH ' . $sequence->getInitialValue() . @@ -185,7 +174,7 @@ public function getCreateSequenceSQL(Sequence $sequence) /** * {@inheritDoc} */ - public function getAlterSequenceSQL(Sequence $sequence) + public function getAlterSequenceSQL(Sequence $sequence) : string { return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() @@ -194,10 +183,8 @@ public function getAlterSequenceSQL(Sequence $sequence) /** * Cache definition for sequences - * - * @return string */ - private function getSequenceCacheSQL(Sequence $sequence) + private function getSequenceCacheSQL(Sequence $sequence) : string { if ($sequence->getCache() === 0) { return ' NOCACHE'; @@ -217,7 +204,7 @@ private function getSequenceCacheSQL(Sequence $sequence) /** * {@inheritDoc} */ - public function getSequenceNextValSQL($sequenceName) + public function getSequenceNextValSQL(string $sequenceName) : string { return 'SELECT ' . $sequenceName . '.nextval FROM DUAL'; } @@ -225,7 +212,7 @@ public function getSequenceNextValSQL($sequenceName) /** * {@inheritDoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } @@ -233,7 +220,7 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritDoc} */ - protected function _getTransactionIsolationLevelSQL($level) + protected function _getTransactionIsolationLevelSQL(int $level) : string { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: @@ -251,7 +238,7 @@ protected function _getTransactionIsolationLevelSQL($level) /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'NUMBER(1)'; } @@ -259,7 +246,7 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { return 'NUMBER(10)'; } @@ -267,7 +254,7 @@ public function getIntegerTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { return 'NUMBER(20)'; } @@ -275,7 +262,7 @@ public function getBigIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { return 'NUMBER(5)'; } @@ -283,7 +270,7 @@ public function getSmallIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIMESTAMP(0)'; } @@ -291,7 +278,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIMESTAMP(0) WITH TIME ZONE'; } @@ -299,7 +286,7 @@ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -307,7 +294,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -315,7 +302,7 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { return ''; } @@ -323,32 +310,39 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarcharTypeDeclarationSQLSnippet(?int $length) : string { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)') - : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)'); + if ($length === null) { + throw ColumnLengthRequired::new($this, 'VARCHAR2'); + } + + return sprintf('VARCHAR2(%d)', $length); } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string { - return 'RAW(' . ($length ?: $this->getBinaryMaxLength()) . ')'; + if ($length === null) { + throw ColumnLengthRequired::new($this, 'RAW'); + } + + return sprintf('RAW(%d)', $length); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getBinaryMaxLength() + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string { - return 2000; + return $this->getBinaryTypeDeclarationSQLSnippet($length); } /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { return 'CLOB'; } @@ -356,7 +350,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getListDatabasesSQL() + public function getListDatabasesSQL() : string { return 'SELECT username FROM all_users'; } @@ -364,40 +358,38 @@ public function getListDatabasesSQL() /** * {@inheritDoc} */ - public function getListSequencesSQL($database) + public function getListSequencesSQL(string $database) : string { - $database = $this->normalizeIdentifier($database); - $database = $this->quoteStringLiteral($database->getName()); - - return 'SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ' . - 'WHERE SEQUENCE_OWNER = ' . $database; + return 'SELECT SEQUENCE_NAME, MIN_VALUE, INCREMENT_BY FROM SYS.ALL_SEQUENCES WHERE SEQUENCE_OWNER = ' + . $this->quoteStringLiteral( + $this->normalizeIdentifier($database)->getName() + ); } /** * {@inheritDoc} */ - protected function _getCreateTableSQL($table, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $indexes = $options['indexes'] ?? []; $options['indexes'] = []; - $sql = parent::_getCreateTableSQL($table, $columns, $options); + $sql = parent::_getCreateTableSQL($tableName, $columns, $options); - foreach ($columns as $name => $column) { + foreach ($columns as $column) { if (isset($column['sequence'])) { $sql[] = $this->getCreateSequenceSQL($column['sequence']); } - if (! isset($column['autoincrement']) || ! $column['autoincrement'] && - (! isset($column['autoinc']) || ! $column['autoinc'])) { + if (empty($column['autoincrement'])) { continue; } - $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table)); + $sql = array_merge($sql, $this->getCreateAutoincrementSql($column['name'], $tableName)); } if (isset($indexes) && ! empty($indexes)) { foreach ($indexes as $index) { - $sql[] = $this->getCreateIndexSQL($index, $table); + $sql[] = $this->getCreateIndexSQL($index, $tableName); } } @@ -409,7 +401,7 @@ protected function _getCreateTableSQL($table, array $columns, array $options = [ * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); @@ -446,7 +438,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return 'SELECT * FROM sys.user_tables'; } @@ -454,7 +446,7 @@ public function getListTablesSQL() /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return 'SELECT view_name, text FROM sys.user_views'; } @@ -462,7 +454,7 @@ public function getListViewsSQL($database) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -470,19 +462,15 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } /** - * @param string $name - * @param string $table - * @param int $start - * - * @return string[] + * @return array */ - public function getCreateAutoincrementSql($name, $table, $start = 1) + public function getCreateAutoincrementSql(string $name, string $table, int $start = 1) : array { $tableIdentifier = $this->normalizeIdentifier($table); $quotedTableName = $tableIdentifier->getQuotedName($this); @@ -546,7 +534,7 @@ public function getCreateAutoincrementSql($name, $table, $start = 1) * * @return string[] */ - public function getDropAutoincrementSql($table) + public function getDropAutoincrementSql(string $table) : array { $table = $this->normalizeIdentifier($table); $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($table); @@ -572,7 +560,7 @@ public function getDropAutoincrementSql($table) * * @return Identifier The normalized identifier. */ - private function normalizeIdentifier($name) + private function normalizeIdentifier(string $name) : Identifier { $identifier = new Identifier($name); @@ -586,10 +574,8 @@ private function normalizeIdentifier($name) * if the given table name is quoted by intention. * * @param Identifier $table The table identifier to return the autoincrement primary key identifier name for. - * - * @return string */ - private function getAutoincrementIdentifierName(Identifier $table) + private function getAutoincrementIdentifierName(Identifier $table) : string { $identifierName = $table->getName() . '_AI_PK'; @@ -601,7 +587,7 @@ private function getAutoincrementIdentifierName(Identifier $table) /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); @@ -633,7 +619,7 @@ public function getListTableForeignKeysSQL($table) /** * {@inheritDoc} */ - public function getListTableConstraintsSQL($table) + public function getListTableConstraintsSQL(string $table) : string { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); @@ -644,7 +630,7 @@ public function getListTableConstraintsSQL($table) /** * {@inheritDoc} */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); @@ -688,7 +674,7 @@ public function getListTableColumnsSQL($table, $database = null) /** * {@inheritDoc} */ - public function getDropSequenceSQL($sequence) + public function getDropSequenceSQL($sequence) : string { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); @@ -700,7 +686,7 @@ public function getDropSequenceSQL($sequence) /** * {@inheritDoc} */ - public function getDropForeignKeySQL($foreignKey, $table) + public function getDropForeignKeySQL($foreignKey, $table) : string { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); @@ -719,7 +705,7 @@ public function getDropForeignKeySQL($foreignKey, $table) /** * {@inheritdoc} */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $referentialAction = null; @@ -733,7 +719,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey /** * {@inheritdoc} */ - public function getForeignKeyReferentialActionSQL($action) + public function getForeignKeyReferentialActionSQL(string $action) : string { $action = strtoupper($action); @@ -750,14 +736,14 @@ public function getForeignKeyReferentialActionSQL($action) default: // SET DEFAULT is not supported, throw exception instead. - throw new InvalidArgumentException('Invalid foreign key action: ' . $action); + throw new InvalidArgumentException(sprintf('Invalid foreign key action "%s".', $action)); } } /** * {@inheritDoc} */ - public function getDropDatabaseSQL($database) + public function getDropDatabaseSQL(string $database) : string { return 'DROP USER ' . $database . ' CASCADE'; } @@ -765,7 +751,7 @@ public function getDropDatabaseSQL($database) /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $sql = []; $commentsSQL = []; @@ -875,7 +861,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $diff->getName($this)->getQuotedName($this), @@ -896,7 +882,7 @@ public function getAlterTableSQL(TableDiff $diff) /** * {@inheritdoc} */ - public function getColumnDeclarationSQL($name, array $field) + public function getColumnDeclarationSQL(string $name, array $field) : string { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); @@ -925,7 +911,7 @@ public function getColumnDeclarationSQL($name, array $field) /** * {@inheritdoc} */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); @@ -938,7 +924,7 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) /** * {@inheritDoc} */ - public function prefersSequences() + public function prefersSequences() : bool { return true; } @@ -946,7 +932,7 @@ public function prefersSequences() /** * {@inheritdoc} */ - public function usesSequenceEmulatedIdentityColumns() + public function usesSequenceEmulatedIdentityColumns() : bool { return true; } @@ -954,7 +940,7 @@ public function usesSequenceEmulatedIdentityColumns() /** * {@inheritdoc} */ - public function getIdentitySequenceName($tableName, $columnName) + public function getIdentitySequenceName(string $tableName, string $columnName) : string { $table = new Identifier($tableName); @@ -973,7 +959,7 @@ public function getIdentitySequenceName($tableName, $columnName) /** * {@inheritDoc} */ - public function supportsCommentOnStatement() + public function supportsCommentOnStatement() : bool { return true; } @@ -981,7 +967,7 @@ public function supportsCommentOnStatement() /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'oracle'; } @@ -989,7 +975,7 @@ public function getName() /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset <= 0) { return $query; @@ -1025,7 +1011,7 @@ protected function doModifyLimitQuery($query, $limit, $offset = null) * * Oracle returns all column names in SQL result sets in uppercase. */ - public function getSQLResultCasing($column) + public function getSQLResultCasing(string $column) : string { return strtoupper($column); } @@ -1033,7 +1019,7 @@ public function getSQLResultCasing($column) /** * {@inheritDoc} */ - public function getCreateTemporaryTableSnippetSQL() + public function getCreateTemporaryTableSnippetSQL() : string { return 'CREATE GLOBAL TEMPORARY TABLE'; } @@ -1041,7 +1027,7 @@ public function getCreateTemporaryTableSnippetSQL() /** * {@inheritDoc} */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString() : string { return 'Y-m-d H:i:sP'; } @@ -1049,7 +1035,7 @@ public function getDateTimeTzFormatString() /** * {@inheritDoc} */ - public function getDateFormatString() + public function getDateFormatString() : string { return 'Y-m-d 00:00:00'; } @@ -1057,7 +1043,7 @@ public function getDateFormatString() /** * {@inheritDoc} */ - public function getTimeFormatString() + public function getTimeFormatString() : string { return '1900-01-01 H:i:s'; } @@ -1065,7 +1051,7 @@ public function getTimeFormatString() /** * {@inheritDoc} */ - public function fixSchemaElementName($schemaElementName) + public function fixSchemaElementName(string $schemaElementName) : string { if (strlen($schemaElementName) > 30) { // Trim it @@ -1078,7 +1064,7 @@ public function fixSchemaElementName($schemaElementName) /** * {@inheritDoc} */ - public function getMaxIdentifierLength() + public function getMaxIdentifierLength() : int { return 30; } @@ -1086,7 +1072,7 @@ public function getMaxIdentifierLength() /** * {@inheritDoc} */ - public function supportsSequences() + public function supportsSequences() : bool { return true; } @@ -1094,7 +1080,7 @@ public function supportsSequences() /** * {@inheritDoc} */ - public function supportsForeignKeyOnUpdate() + public function supportsForeignKeyOnUpdate() : bool { return false; } @@ -1102,7 +1088,7 @@ public function supportsForeignKeyOnUpdate() /** * {@inheritDoc} */ - public function supportsReleaseSavepoints() + public function supportsReleaseSavepoints() : bool { return false; } @@ -1110,7 +1096,7 @@ public function supportsReleaseSavepoints() /** * {@inheritDoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); @@ -1120,49 +1106,47 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * {@inheritDoc} */ - public function getDummySelectSQL() + public function getDummySelectSQL(string $expression = '1') : string { - $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; - return sprintf('SELECT %s FROM DUAL', $expression); } /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'integer' => 'integer', - 'number' => 'integer', - 'pls_integer' => 'boolean', - 'binary_integer' => 'boolean', - 'varchar' => 'string', - 'varchar2' => 'string', - 'nvarchar2' => 'string', - 'char' => 'string', - 'nchar' => 'string', - 'date' => 'date', - 'timestamp' => 'datetime', - 'timestamptz' => 'datetimetz', - 'float' => 'float', - 'binary_float' => 'float', - 'binary_double' => 'float', - 'long' => 'string', - 'clob' => 'text', - 'nclob' => 'text', - 'raw' => 'binary', - 'long raw' => 'blob', - 'rowid' => 'string', - 'urowid' => 'string', - 'blob' => 'blob', + 'binary_double' => 'float', + 'binary_float' => 'float', + 'binary_integer' => 'boolean', + 'blob' => 'blob', + 'char' => 'string', + 'clob' => 'text', + 'date' => 'date', + 'float' => 'float', + 'integer' => 'integer', + 'long' => 'string', + 'long raw' => 'blob', + 'nchar' => 'string', + 'nclob' => 'text', + 'number' => 'integer', + 'nvarchar2' => 'string', + 'pls_integer' => 'boolean', + 'raw' => 'binary', + 'rowid' => 'string', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'urowid' => 'string', + 'varchar' => 'string', + 'varchar2' => 'string', ]; } /** * {@inheritDoc} */ - public function releaseSavePoint($savepoint) + public function releaseSavePoint(string $savepoint) : string { return ''; } @@ -1170,7 +1154,7 @@ public function releaseSavePoint($savepoint) /** * {@inheritDoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\OracleKeywords::class; } @@ -1178,7 +1162,7 @@ protected function getReservedKeywordsClass() /** * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { return 'BLOB'; } diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php index cfb079f94dd..9704a6c3b41 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php @@ -19,7 +19,7 @@ protected function getReservedKeywordsClass() : string return PostgreSQL100Keywords::class; } - public function getListSequencesSQL($database) : string + public function getListSequencesSQL(string $database) : string { return 'SELECT sequence_name AS relname, sequence_schema AS schemaname, diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php deleted file mode 100644 index f558409831c..00000000000 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php +++ /dev/null @@ -1,46 +0,0 @@ -quoteSingleIdentifier($collation); - } - - /** - * {@inheritDoc} - */ - public function getListTableColumnsSQL($table, $database = null) - { - $sql = parent::getListTableColumnsSQL($table, $database); - $parts = explode('AS complete_type,', $sql, 2); - - return $parts[0] . 'AS complete_type, (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,' . $parts[1]; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php deleted file mode 100644 index 1703056143f..00000000000 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php +++ /dev/null @@ -1,69 +0,0 @@ -doctrineTypeMapping['json'] = Types::JSON; - } - - /** - * {@inheritdoc} - */ - public function getCloseActiveDatabaseConnectionsSQL($database) - { - return sprintf( - 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = %s', - $this->quoteStringLiteral($database) - ); - } -} diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php b/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php index fb559dea2ac..59841153a5e 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php @@ -1,5 +1,7 @@ useBooleanTrueFalseStrings = (bool) $flag; + $this->useBooleanTrueFalseStrings = $flag; } /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from, $length = null) - { - if ($length === null) { - return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; - } - - return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; - } - - /** - * {@inheritDoc} - */ - public function getNowExpression() + public function getNowExpression() : string { return 'LOCALTIMESTAMP(0)'; } @@ -98,7 +85,7 @@ public function getNowExpression() /** * {@inheritDoc} */ - public function getRegexpExpression() + public function getRegexpExpression() : string { return 'SIMILAR TO'; } @@ -106,25 +93,25 @@ public function getRegexpExpression() /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos !== false) { - $str = $this->getSubstringExpression($str, $startPos); + if ($start !== null) { + $string = $this->getSubstringExpression($string, $start); - return 'CASE WHEN (POSITION(' . $substr . ' IN ' . $str . ') = 0) THEN 0 ELSE (POSITION(' . $substr . ' IN ' . $str . ') + ' . ($startPos-1) . ') END'; + return 'CASE WHEN (POSITION(' . $substring . ' IN ' . $string . ') = 0) THEN 0 ELSE (POSITION(' . $substring . ' IN ' . $string . ') + ' . $start . ' - 1) END'; } - return 'POSITION(' . $substr . ' IN ' . $str . ')'; + return sprintf('POSITION(%s IN %s)', $substring, $string); } /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { if ($unit === DateIntervalUnit::QUARTER) { - $interval *= 3; - $unit = DateIntervalUnit::MONTH; + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; } return '(' . $date . ' ' . $operator . ' (' . $interval . " || ' " . $unit . "')::interval)"; @@ -133,7 +120,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))'; } @@ -141,7 +128,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - public function supportsSequences() + public function supportsSequences() : bool { return true; } @@ -149,7 +136,7 @@ public function supportsSequences() /** * {@inheritDoc} */ - public function supportsSchemas() + public function supportsSchemas() : bool { return true; } @@ -157,7 +144,7 @@ public function supportsSchemas() /** * {@inheritdoc} */ - public function getDefaultSchemaName() + public function getDefaultSchemaName() : string { return 'public'; } @@ -165,7 +152,7 @@ public function getDefaultSchemaName() /** * {@inheritDoc} */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return true; } @@ -173,7 +160,7 @@ public function supportsIdentityColumns() /** * {@inheritdoc} */ - public function supportsPartialIndexes() + public function supportsPartialIndexes() : bool { return true; } @@ -181,7 +168,7 @@ public function supportsPartialIndexes() /** * {@inheritdoc} */ - public function usesSequenceEmulatedIdentityColumns() + public function usesSequenceEmulatedIdentityColumns() : bool { return true; } @@ -189,7 +176,7 @@ public function usesSequenceEmulatedIdentityColumns() /** * {@inheritdoc} */ - public function getIdentitySequenceName($tableName, $columnName) + public function getIdentitySequenceName(string $tableName, string $columnName) : string { return $tableName . '_' . $columnName . '_seq'; } @@ -197,7 +184,7 @@ public function getIdentitySequenceName($tableName, $columnName) /** * {@inheritDoc} */ - public function supportsCommentOnStatement() + public function supportsCommentOnStatement() : bool { return true; } @@ -205,7 +192,7 @@ public function supportsCommentOnStatement() /** * {@inheritDoc} */ - public function prefersSequences() + public function prefersSequences() : bool { return true; } @@ -213,7 +200,7 @@ public function prefersSequences() /** * {@inheritDoc} */ - public function hasNativeGuidType() + public function hasNativeGuidType() : bool { return true; } @@ -221,7 +208,7 @@ public function hasNativeGuidType() /** * {@inheritDoc} */ - public function getListDatabasesSQL() + public function getListDatabasesSQL() : string { return 'SELECT datname FROM pg_database'; } @@ -229,7 +216,7 @@ public function getListDatabasesSQL() /** * {@inheritDoc} */ - public function getListNamespacesSQL() + public function getListNamespacesSQL() : string { return "SELECT schema_name AS nspname FROM information_schema.schemata @@ -240,7 +227,7 @@ public function getListNamespacesSQL() /** * {@inheritDoc} */ - public function getListSequencesSQL($database) + public function getListSequencesSQL(string $database) : string { return "SELECT sequence_name AS relname, sequence_schema AS schemaname @@ -252,7 +239,7 @@ public function getListSequencesSQL($database) /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return "SELECT quote_ident(table_name) AS table_name, table_schema AS schema_name @@ -267,7 +254,7 @@ public function getListTablesSQL() /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return 'SELECT quote_ident(table_name) AS viewname, table_schema AS schemaname, @@ -279,7 +266,7 @@ public function getListViewsSQL($database) /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table, $database = null) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { return 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r @@ -295,7 +282,7 @@ public function getListTableForeignKeysSQL($table, $database = null) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -303,7 +290,7 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } @@ -311,7 +298,7 @@ public function getDropViewSQL($name) /** * {@inheritDoc} */ - public function getListTableConstraintsSQL($table) + public function getListTableConstraintsSQL(string $table) : string { $table = new Identifier($table); $table = $this->quoteStringLiteral($table->getName()); @@ -340,7 +327,7 @@ public function getListTableConstraintsSQL($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { return 'SELECT quote_ident(relname) as relname, pg_index.indisunique, pg_index.indisprimary, pg_index.indkey, pg_index.indrelid, @@ -353,14 +340,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) ) AND pg_index.indexrelid = oid'; } - /** - * @param string $table - * @param string $classAlias - * @param string $namespaceAlias - * - * @return string - */ - private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n') + private function getTableWhereClause(string $table, string $classAlias = 'c', string $namespaceAlias = 'n') : string { $whereClause = $namespaceAlias . ".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND "; if (strpos($table, '.') !== false) { @@ -385,13 +365,14 @@ private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias /** * {@inheritDoc} */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { return "SELECT a.attnum, quote_ident(a.attname) AS field, t.typname AS type, format_type(a.atttypid, a.atttypmod) AS complete_type, + (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation, (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type, @@ -422,9 +403,9 @@ public function getListTableColumnsSQL($table, $database = null) /** * {@inheritDoc} */ - public function getCreateDatabaseSQL($name) + public function getCreateDatabaseSQL(string $database) : string { - return 'CREATE DATABASE ' . $name; + return 'CREATE DATABASE ' . $database; } /** @@ -433,10 +414,8 @@ public function getCreateDatabaseSQL($name) * This is useful to force DROP DATABASE operations which could fail because of active connections. * * @param string $database The name of the database to disallow new connections for. - * - * @return string */ - public function getDisallowDatabaseConnectionsSQL($database) + public function getDisallowDatabaseConnectionsSQL(string $database) : string { return "UPDATE pg_database SET datallowconn = 'false' WHERE datname = " . $this->quoteStringLiteral($database); } @@ -447,19 +426,17 @@ public function getDisallowDatabaseConnectionsSQL($database) * This is useful to force DROP DATABASE operations which could fail because of active connections. * * @param string $database The name of the database to close currently active connections for. - * - * @return string */ - public function getCloseActiveDatabaseConnectionsSQL($database) + public function getCloseActiveDatabaseConnectionsSQL(string $database) : string { - return 'SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = ' + return 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = ' . $this->quoteStringLiteral($database); } /** * {@inheritDoc} */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $query = ''; @@ -475,9 +452,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey $query .= ' NOT DEFERRABLE'; } - if (($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) - || ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) - ) { + if ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) { $query .= ' INITIALLY DEFERRED'; } else { $query .= ' INITIALLY IMMEDIATE'; @@ -489,7 +464,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $sql = []; $commentsSQL = []; @@ -616,7 +591,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $diff->getName($this)->getQuotedName($this), @@ -648,7 +623,7 @@ public function getAlterTableSQL(TableDiff $diff) * * @return bool True if the given column diff is an unchanged binary type column, false otherwise. */ - private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) + private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) : bool { $columnType = $columnDiff->column->getType(); @@ -656,9 +631,9 @@ private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) return false; } - $fromColumn = $columnDiff->fromColumn instanceof Column ? $columnDiff->fromColumn : null; + $fromColumn = $columnDiff->fromColumn; - if ($fromColumn) { + if ($fromColumn !== null) { $fromColumnType = $fromColumn->getType(); if (! $fromColumnType instanceof BinaryType && ! $fromColumnType instanceof BlobType) { @@ -678,7 +653,7 @@ private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) /** * {@inheritdoc} */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); @@ -691,7 +666,7 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) /** * {@inheritdoc} */ - public function getCommentOnColumnSQL($tableName, $columnName, $comment) + public function getCommentOnColumnSQL(string $tableName, string $columnName, ?string $comment) : string { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); @@ -708,7 +683,7 @@ public function getCommentOnColumnSQL($tableName, $columnName, $comment) /** * {@inheritDoc} */ - public function getCreateSequenceSQL(Sequence $sequence) + public function getCreateSequenceSQL(Sequence $sequence) : string { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . @@ -720,7 +695,7 @@ public function getCreateSequenceSQL(Sequence $sequence) /** * {@inheritDoc} */ - public function getAlterSequenceSQL(Sequence $sequence) + public function getAlterSequenceSQL(Sequence $sequence) : string { return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . @@ -729,10 +704,8 @@ public function getAlterSequenceSQL(Sequence $sequence) /** * Cache definition for sequences - * - * @return string */ - private function getSequenceCacheSQL(Sequence $sequence) + private function getSequenceCacheSQL(Sequence $sequence) : string { if ($sequence->getCache() > 1) { return ' CACHE ' . $sequence->getCache(); @@ -744,7 +717,7 @@ private function getSequenceCacheSQL(Sequence $sequence) /** * {@inheritDoc} */ - public function getDropSequenceSQL($sequence) + public function getDropSequenceSQL($sequence) : string { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); @@ -756,7 +729,7 @@ public function getDropSequenceSQL($sequence) /** * {@inheritDoc} */ - public function getCreateSchemaSQL($schemaName) + public function getCreateSchemaSQL(string $schemaName) : string { return 'CREATE SCHEMA ' . $schemaName; } @@ -764,7 +737,7 @@ public function getCreateSchemaSQL($schemaName) /** * {@inheritDoc} */ - public function getDropForeignKeySQL($foreignKey, $table) + public function getDropForeignKeySQL($foreignKey, $table) : string { return $this->getDropConstraintSQL($foreignKey, $table); } @@ -772,7 +745,7 @@ public function getDropForeignKeySQL($foreignKey, $table) /** * {@inheritDoc} */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $queryFields = $this->getColumnDeclarationListSQL($columns); @@ -814,7 +787,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options * * @throws UnexpectedValueException */ - private function convertSingleBooleanValue($value, $callback) + private function convertSingleBooleanValue($value, callable $callback) { if ($value === null) { return $callback(null); @@ -839,7 +812,10 @@ private function convertSingleBooleanValue($value, $callback) return $callback(true); } - throw new UnexpectedValueException("Unrecognized boolean literal '${value}'"); + throw new UnexpectedValueException(sprintf( + 'Unrecognized boolean literal, %s given.', + $value + )); } /** @@ -854,7 +830,7 @@ private function convertSingleBooleanValue($value, $callback) * * @return mixed */ - private function doConvertBooleans($item, $callback) + private function doConvertBooleans($item, callable $callback) { if (is_array($item)) { foreach ($item as $key => $value) { @@ -880,7 +856,7 @@ public function convertBooleans($item) return $this->doConvertBooleans( $item, - static function ($boolean) { + static function ($boolean) : string { if ($boolean === null) { return 'NULL'; } @@ -901,7 +877,7 @@ public function convertBooleansToDatabaseValue($item) return $this->doConvertBooleans( $item, - static function ($boolean) { + static function ($boolean) : ?int { return $boolean === null ? null : (int) $boolean; } ); @@ -910,9 +886,9 @@ static function ($boolean) { /** * {@inheritDoc} */ - public function convertFromBoolean($item) + public function convertFromBoolean($item) : ?bool { - if (in_array(strtolower($item), $this->booleanLiterals['false'], true)) { + if (in_array($item, $this->booleanLiterals['false'], true)) { return false; } @@ -922,7 +898,7 @@ public function convertFromBoolean($item) /** * {@inheritDoc} */ - public function getSequenceNextValSQL($sequenceName) + public function getSequenceNextValSQL(string $sequenceName) : string { return "SELECT NEXTVAL('" . $sequenceName . "')"; } @@ -930,7 +906,7 @@ public function getSequenceNextValSQL($sequenceName) /** * {@inheritDoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); @@ -939,7 +915,7 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'BOOLEAN'; } @@ -947,9 +923,9 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { - if (! empty($field['autoincrement'])) { + if (! empty($columnDef['autoincrement'])) { return 'SERIAL'; } @@ -959,9 +935,9 @@ public function getIntegerTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { - if (! empty($field['autoincrement'])) { + if (! empty($columnDef['autoincrement'])) { return 'BIGSERIAL'; } @@ -971,15 +947,19 @@ public function getBigIntTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { + if (! empty($columnDef['autoincrement'])) { + return 'SMALLSERIAL'; + } + return 'SMALLINT'; } /** * {@inheritDoc} */ - public function getGuidTypeDeclarationSQL(array $field) + public function getGuidTypeDeclarationSQL(array $column) : string { return 'UUID'; } @@ -987,7 +967,7 @@ public function getGuidTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIMESTAMP(0) WITHOUT TIME ZONE'; } @@ -995,7 +975,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIMESTAMP(0) WITH TIME ZONE'; } @@ -1003,7 +983,7 @@ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -1011,42 +991,45 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIME(0) WITHOUT TIME ZONE'; } /** * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead */ - public function getGuidExpression() + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { - return 'UUID_GENERATE_V4()'; + return ''; } /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function getVarcharTypeDeclarationSQLSnippet(?int $length) : string { - return ''; + $sql = 'VARCHAR'; + + if ($length !== null) { + $sql .= sprintf('(%d)', $length); + } + + return $sql; } /** * {@inheritDoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') - : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + return 'BYTEA'; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string { return 'BYTEA'; } @@ -1054,7 +1037,7 @@ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { return 'TEXT'; } @@ -1062,7 +1045,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'postgresql'; } @@ -1072,7 +1055,7 @@ public function getName() * * PostgreSQL returns all column names in SQL result sets in lowercase. */ - public function getSQLResultCasing($column) + public function getSQLResultCasing(string $column) : string { return strtolower($column); } @@ -1080,7 +1063,7 @@ public function getSQLResultCasing($column) /** * {@inheritDoc} */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString() : string { return 'Y-m-d H:i:sO'; } @@ -1088,15 +1071,15 @@ public function getDateTimeTzFormatString() /** * {@inheritDoc} */ - public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + public function getEmptyIdentityInsertSQL(string $tableName, string $identifierColumnName) : string { - return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)'; + return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)'; } /** * {@inheritDoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); $sql = 'TRUNCATE ' . $tableIdentifier->getQuotedName($this); @@ -1111,7 +1094,7 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * {@inheritDoc} */ - public function getReadLockSQL() + public function getReadLockSQL() : string { return 'FOR SHARE'; } @@ -1119,101 +1102,110 @@ public function getReadLockSQL() /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'smallint' => 'smallint', - 'int2' => 'smallint', - 'serial' => 'integer', - 'serial4' => 'integer', - 'int' => 'integer', - 'int4' => 'integer', - 'integer' => 'integer', - 'bigserial' => 'bigint', - 'serial8' => 'bigint', - 'bigint' => 'bigint', - 'int8' => 'bigint', - 'bool' => 'boolean', - 'boolean' => 'boolean', - 'text' => 'text', - 'tsvector' => 'text', - 'varchar' => 'string', - 'interval' => 'string', - '_varchar' => 'string', - 'char' => 'string', - 'bpchar' => 'string', - 'inet' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'timestamptz' => 'datetimetz', - 'time' => 'time', - 'timetz' => 'time', - 'float' => 'float', - 'float4' => 'float', - 'float8' => 'float', - 'double' => 'float', + 'bigint' => 'bigint', + 'bigserial' => 'bigint', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'bpchar' => 'string', + 'bytea' => 'blob', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'decimal' => 'decimal', + 'double' => 'float', 'double precision' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', - 'money' => 'decimal', - 'numeric' => 'decimal', - 'year' => 'date', - 'uuid' => 'guid', - 'bytea' => 'blob', + 'float' => 'float', + 'float4' => 'float', + 'float8' => 'float', + 'inet' => 'string', + 'int' => 'integer', + 'int2' => 'smallint', + 'int4' => 'integer', + 'int8' => 'bigint', + 'integer' => 'integer', + 'interval' => 'string', + 'json' => Type::JSON, + 'money' => 'decimal', + 'numeric' => 'decimal', + 'serial' => 'integer', + 'serial4' => 'integer', + 'serial8' => 'bigint', + 'real' => 'float', + 'smallint' => 'smallint', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'timetz' => 'time', + 'tsvector' => 'text', + 'uuid' => 'guid', + 'varchar' => 'string', + 'year' => 'date', + '_varchar' => 'string', ]; } + /** + * {@inheritdoc} + */ + public function hasNativeJsonType() : bool + { + return true; + } + /** * {@inheritDoc} */ - public function getVarcharMaxLength() + protected function getReservedKeywordsClass() : string { - return 65535; + return Keywords\PostgreSQLKeywords::class; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getBinaryMaxLength() + public function getBlobTypeDeclarationSQL(array $field) : string { - return 0; + return 'BYTEA'; } /** * {@inheritdoc} */ - public function getBinaryDefaultLength() + public function getDefaultValueDeclarationSQL(array $field) : string { - return 0; + if ($this->isSerialField($field)) { + return ''; + } + + return parent::getDefaultValueDeclarationSQL($field); } /** - * {@inheritDoc} + * {@inheritdoc} */ - protected function getReservedKeywordsClass() + public function supportsColumnCollation() : bool { - return Keywords\PostgreSQLKeywords::class; + return true; } /** - * {@inheritDoc} + * {@inheritdoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getColumnCollationDeclarationSQL(string $collation) : string { - return 'BYTEA'; + return 'COLLATE ' . $this->quoteSingleIdentifier($collation); } /** * {@inheritdoc} */ - public function getDefaultValueDeclarationSQL($field) + public function getJsonTypeDeclarationSQL(array $field) : string { - if ($this->isSerialField($field)) { - return ''; - } - - return parent::getDefaultValueDeclarationSQL($field); + return 'JSON'; } /** @@ -1231,7 +1223,7 @@ private function isSerialField(array $field) : bool */ private function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff) : bool { - if (! $columnDiff->fromColumn) { + if ($columnDiff->fromColumn === null) { return $columnDiff->hasChanged('type'); } @@ -1250,6 +1242,10 @@ private function isNumericType(Type $type) : bool private function getOldColumnComment(ColumnDiff $columnDiff) : ?string { - return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null; + if ($columnDiff->fromColumn === null) { + return null; + } + + return $this->getColumnComment($columnDiff->fromColumn); } } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php deleted file mode 100644 index a46ae9352c4..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php +++ /dev/null @@ -1,26 +0,0 @@ -getQuotedName($this) . - ' INCREMENT BY ' . $sequence->getAllocationSize() . - ' START WITH ' . $sequence->getInitialValue() . - ' MINVALUE ' . $sequence->getInitialValue(); - } - - /** - * {@inheritdoc} - */ - public function getAlterSequenceSQL(Sequence $sequence) - { - return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . - ' INCREMENT BY ' . $sequence->getAllocationSize(); - } - - /** - * {@inheritdoc} - */ - public function getDateTimeTzFormatString() - { - return 'Y-m-d H:i:s.uP'; - } - - /** - * {@inheritdoc} - */ - public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) - { - return 'TIMESTAMP WITH TIME ZONE'; - } - - /** - * {@inheritdoc} - */ - public function getDropSequenceSQL($sequence) - { - if ($sequence instanceof Sequence) { - $sequence = $sequence->getQuotedName($this); - } - - return 'DROP SEQUENCE ' . $sequence; - } - - /** - * {@inheritdoc} - */ - public function getListSequencesSQL($database) - { - return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; - } - - /** - * {@inheritdoc} - */ - public function getSequenceNextValSQL($sequenceName) - { - return 'SELECT ' . $sequenceName . '.NEXTVAL'; - } - - /** - * {@inheritdoc} - */ - public function supportsSequences() - { - return true; - } - - /** - * {@inheritdoc} - */ - protected function getAdvancedIndexOptionsSQL(Index $index) - { - if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { - return ' WITH NULLS NOT DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); - } - - return parent::getAdvancedIndexOptionsSQL($index); - } - - /** - * {@inheritdoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLAnywhere12Keywords::class; - } - - /** - * {@inheritDoc} - */ - protected function initializeDoctrineTypeMappings() - { - parent::initializeDoctrineTypeMappings(); - $this->doctrineTypeMapping['timestamp with time zone'] = 'datetime'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php deleted file mode 100644 index 35d4238e4a3..00000000000 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php +++ /dev/null @@ -1,39 +0,0 @@ -hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { - throw new UnexpectedValueException( - 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' - ); - } - - if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { - return ' WITH NULLS DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); - } - - return parent::getAdvancedIndexOptionsSQL($index); - } - - /** - * {@inheritdoc} - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLAnywhere16Keywords::class; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php index 6e3b2fcb958..935fe988bf5 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php @@ -1,27 +1,31 @@ getMaxIdentifierLength(); @@ -80,7 +84,7 @@ public function fixSchemaElementName($schemaElementName) /** * {@inheritdoc} */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $query = ''; @@ -108,7 +112,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey /** * {@inheritdoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $sql = []; $columnSql = []; @@ -186,7 +190,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . $this->getAlterTableRenameTableClause($newName); } @@ -205,10 +209,8 @@ public function getAlterTableSQL(TableDiff $diff) * Returns the SQL clause for creating a column in a table alteration. * * @param Column $column The column to add. - * - * @return string */ - protected function getAlterTableAddColumnClause(Column $column) + protected function getAlterTableAddColumnClause(Column $column) : string { return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); } @@ -217,10 +219,8 @@ protected function getAlterTableAddColumnClause(Column $column) * Returns the SQL clause for altering a table. * * @param Identifier $tableName The quoted name of the table to alter. - * - * @return string */ - protected function getAlterTableClause(Identifier $tableName) + protected function getAlterTableClause(Identifier $tableName) : string { return 'ALTER TABLE ' . $tableName->getQuotedName($this); } @@ -229,10 +229,8 @@ protected function getAlterTableClause(Identifier $tableName) * Returns the SQL clause for dropping a column in a table alteration. * * @param Column $column The column to drop. - * - * @return string */ - protected function getAlterTableRemoveColumnClause(Column $column) + protected function getAlterTableRemoveColumnClause(Column $column) : string { return 'DROP ' . $column->getQuotedName($this); } @@ -242,10 +240,8 @@ protected function getAlterTableRemoveColumnClause(Column $column) * * @param string $oldColumnName The quoted name of the column to rename. * @param Column $column The column to rename to. - * - * @return string */ - protected function getAlterTableRenameColumnClause($oldColumnName, Column $column) + protected function getAlterTableRenameColumnClause(string $oldColumnName, Column $column) : string { $oldColumnName = new Identifier($oldColumnName); @@ -256,10 +252,8 @@ protected function getAlterTableRenameColumnClause($oldColumnName, Column $colum * Returns the SQL clause for renaming a table in a table alteration. * * @param Identifier $newTableName The quoted name of the table to rename to. - * - * @return string */ - protected function getAlterTableRenameTableClause(Identifier $newTableName) + protected function getAlterTableRenameTableClause(Identifier $newTableName) : string { return 'RENAME ' . $newTableName->getQuotedName($this); } @@ -271,10 +265,8 @@ protected function getAlterTableRenameTableClause(Identifier $newTableName) * Changes in column comments have to be handled differently. * * @param ColumnDiff $columnDiff The diff of the column to alter. - * - * @return string|null */ - protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff) + protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff) : ?string { $column = $columnDiff->column; @@ -296,7 +288,7 @@ protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff) /** * {@inheritdoc} */ - public function getBigIntTypeDeclarationSQL(array $columnDef) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { $columnDef['integer_type'] = 'BIGINT'; @@ -306,23 +298,7 @@ public function getBigIntTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - public function getBinaryDefaultLength() - { - return 1; - } - - /** - * {@inheritdoc} - */ - public function getBinaryMaxLength() - { - return 32767; - } - - /** - * {@inheritdoc} - */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { return 'LONG BINARY'; } @@ -335,7 +311,7 @@ public function getBlobTypeDeclarationSQL(array $field) * Otherwise by just omitting the NOT NULL clause, * SQL Anywhere will declare them NOT NULL nonetheless. */ - public function getBooleanTypeDeclarationSQL(array $columnDef) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { $nullClause = isset($columnDef['notnull']) && (bool) $columnDef['notnull'] === false ? ' NULL' : ''; @@ -345,7 +321,7 @@ public function getBooleanTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { return 'TEXT'; } @@ -353,7 +329,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritdoc} */ - public function getCommentOnColumnSQL($tableName, $columnName, $comment) + public function getCommentOnColumnSQL(string $tableName, string $columnName, ?string $comment) : string { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); @@ -370,15 +346,15 @@ public function getCommentOnColumnSQL($tableName, $columnName, $comment) /** * {@inheritdoc} */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - return 'STRING(' . implode(', ', (array) func_get_args()) . ')'; + return 'STRING(' . implode(', ', $string) . ')'; } /** * {@inheritdoc} */ - public function getCreateConstraintSQL(Constraint $constraint, $table) + public function getCreateConstraintSQL(Constraint $constraint, $table) : string { if ($constraint instanceof ForeignKeyConstraint) { return $this->getCreateForeignKeySQL($constraint, $table); @@ -395,7 +371,7 @@ public function getCreateConstraintSQL(Constraint $constraint, $table) /** * {@inheritdoc} */ - public function getCreateDatabaseSQL($database) + public function getCreateDatabaseSQL(string $database) : string { $database = new Identifier($database); @@ -407,7 +383,7 @@ public function getCreateDatabaseSQL($database) * * Appends SQL Anywhere specific flags if given. */ - public function getCreateIndexSQL(Index $index, $table) + public function getCreateIndexSQL(Index $index, $table) : string { return parent::getCreateIndexSQL($index, $table) . $this->getAdvancedIndexOptionsSQL($index); } @@ -415,7 +391,7 @@ public function getCreateIndexSQL(Index $index, $table) /** * {@inheritdoc} */ - public function getCreatePrimaryKeySQL(Index $index, $table) + public function getCreatePrimaryKeySQL(Index $index, $table) : string { if ($table instanceof Table) { $table = $table->getQuotedName($this); @@ -427,7 +403,7 @@ public function getCreatePrimaryKeySQL(Index $index, $table) /** * {@inheritdoc} */ - public function getCreateTemporaryTableSnippetSQL() + public function getCreateTemporaryTableSnippetSQL() : string { return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE'; } @@ -435,7 +411,7 @@ public function getCreateTemporaryTableSnippetSQL() /** * {@inheritdoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -443,7 +419,7 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritdoc} */ - public function getCurrentDateSQL() + public function getCurrentDateSQL() : string { return 'CURRENT DATE'; } @@ -451,7 +427,7 @@ public function getCurrentDateSQL() /** * {@inheritdoc} */ - public function getCurrentTimeSQL() + public function getCurrentTimeSQL() : string { return 'CURRENT TIME'; } @@ -459,7 +435,7 @@ public function getCurrentTimeSQL() /** * {@inheritdoc} */ - public function getCurrentTimestampSQL() + public function getCurrentTimestampSQL() : string { return 'CURRENT TIMESTAMP'; } @@ -467,7 +443,7 @@ public function getCurrentTimestampSQL() /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { $factorClause = ''; @@ -481,7 +457,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritdoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')'; } @@ -489,7 +465,7 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritdoc} */ - public function getDateTimeFormatString() + public function getDateTimeFormatString() : string { return 'Y-m-d H:i:s.u'; } @@ -497,7 +473,7 @@ public function getDateTimeFormatString() /** * {@inheritdoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATETIME'; } @@ -505,15 +481,15 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritdoc} */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString() : string { - return $this->getDateTimeFormatString(); + return 'Y-m-d H:i:s.uP'; } /** * {@inheritdoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -521,7 +497,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritdoc} */ - public function getDefaultTransactionIsolationLevel() + public function getDefaultTransactionIsolationLevel() : int { return TransactionIsolationLevel::READ_UNCOMMITTED; } @@ -529,7 +505,7 @@ public function getDefaultTransactionIsolationLevel() /** * {@inheritdoc} */ - public function getDropDatabaseSQL($database) + public function getDropDatabaseSQL(string $database) : string { $database = new Identifier($database); @@ -539,7 +515,7 @@ public function getDropDatabaseSQL($database) /** * {@inheritdoc} */ - public function getDropIndexSQL($index, $table = null) + public function getDropIndexSQL($index, $table = null) : string { if ($index instanceof Index) { $index = $index->getQuotedName($this); @@ -547,7 +523,7 @@ public function getDropIndexSQL($index, $table = null) if (! is_string($index)) { throw new InvalidArgumentException( - 'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' . Index::class . '.' + sprintf('SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be a string or an instance of %s.', Index::class) ); } @@ -561,7 +537,7 @@ public function getDropIndexSQL($index, $table = null) if (! is_string($table)) { throw new InvalidArgumentException( - 'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' . Index::class . '.' + sprintf('SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be a string or an instance of %s.', Index::class) ); } @@ -571,7 +547,7 @@ public function getDropIndexSQL($index, $table = null) /** * {@inheritdoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } @@ -579,7 +555,7 @@ public function getDropViewSQL($name) /** * {@inheritdoc} */ - public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) + public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) : string { $sql = ''; $foreignKeyName = $foreignKey->getName(); @@ -592,15 +568,15 @@ public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey } if (empty($localColumns)) { - throw new InvalidArgumentException("Incomplete definition. 'local' required."); + throw new InvalidArgumentException('Incomplete definition. "local" required.'); } if (empty($foreignColumns)) { - throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); + throw new InvalidArgumentException('Incomplete definition. "foreign" required.'); } if (empty($foreignTableName)) { - throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); + throw new InvalidArgumentException('Incomplete definition. "foreignTable" required.'); } if ($foreignKey->hasOption('notnull') && (bool) $foreignKey->getOption('notnull')) { @@ -618,13 +594,11 @@ public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey * * @param int $type The foreign key match type * - * @return string - * * @throws InvalidArgumentException If unknown match type given. */ - public function getForeignKeyMatchClauseSQL($type) + public function getForeignKeyMatchClauseSQL(int $type) : string { - switch ((int) $type) { + switch ($type) { case self::FOREIGN_KEY_MATCH_SIMPLE: return 'SIMPLE'; @@ -640,14 +614,14 @@ public function getForeignKeyMatchClauseSQL($type) case self::FOREIGN_KEY_MATCH_FULL_UNIQUE: return 'UNIQUE FULL'; default: - throw new InvalidArgumentException('Invalid foreign key match type: ' . $type); + throw new InvalidArgumentException(sprintf('Invalid foreign key match type "%s".', $type)); } } /** * {@inheritdoc} */ - public function getForeignKeyReferentialActionSQL($action) + public function getForeignKeyReferentialActionSQL(string $action) : string { // NO ACTION is not supported, therefore falling back to RESTRICT. if (strtoupper($action) === 'NO ACTION') { @@ -660,25 +634,15 @@ public function getForeignKeyReferentialActionSQL($action) /** * {@inheritdoc} */ - public function getForUpdateSQL() + public function getForUpdateSQL() : string { return ''; } /** * {@inheritdoc} - * - * @deprecated Use application-generated UUIDs instead */ - public function getGuidExpression() - { - return 'NEWID()'; - } - - /** - * {@inheritdoc} - */ - public function getGuidTypeDeclarationSQL(array $field) + public function getGuidTypeDeclarationSQL(array $column) : string { return 'UNIQUEIDENTIFIER'; } @@ -686,16 +650,16 @@ public function getGuidTypeDeclarationSQL(array $field) /** * {@inheritdoc} */ - public function getIndexDeclarationSQL($name, Index $index) + public function getIndexDeclarationSQL(string $name, Index $index) : string { // Index declaration in statements like CREATE TABLE is not supported. - throw DBALException::notSupported(__METHOD__); + throw NotSupported::new(__METHOD__); } /** * {@inheritdoc} */ - public function getIntegerTypeDeclarationSQL(array $columnDef) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { $columnDef['integer_type'] = 'INT'; @@ -705,7 +669,7 @@ public function getIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - public function getListDatabasesSQL() + public function getListDatabasesSQL() : string { return 'SELECT db_name(number) AS name FROM sa_db_list()'; } @@ -713,7 +677,7 @@ public function getListDatabasesSQL() /** * {@inheritdoc} */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { $user = 'USER_NAME()'; @@ -752,7 +716,7 @@ public function getListTableColumnsSQL($table, $database = null) * * @todo Where is this used? Which information should be retrieved? */ - public function getListTableConstraintsSQL($table) + public function getListTableConstraintsSQL(string $table) : string { $user = ''; @@ -781,7 +745,7 @@ public function getListTableConstraintsSQL($table) /** * {@inheritdoc} */ - public function getListTableForeignKeysSQL($table) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { $user = ''; @@ -874,7 +838,7 @@ public function getListTableForeignKeysSQL($table) /** * {@inheritdoc} */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { $user = ''; @@ -934,7 +898,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritdoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return "SELECT tbl.table_name FROM SYS.SYSTAB AS tbl @@ -951,7 +915,7 @@ public function getListTablesSQL() * * @todo Where is this used? Which information should be retrieved? */ - public function getListUsersSQL() + public function getListUsersSQL() : string { return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC'; } @@ -959,7 +923,7 @@ public function getListUsersSQL() /** * {@inheritdoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return "SELECT tbl.table_name, v.view_def FROM SYS.SYSVIEW v @@ -973,19 +937,19 @@ public function getListViewsSQL($database) /** * {@inheritdoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'LOCATE(' . $str . ', ' . $substr . ')'; + if ($start === null) { + return sprintf('LOCATE(%s, %s)', $string, $substring); } - return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')'; + return sprintf('LOCATE(%s, %s, %s)', $string, $substring, $start); } /** * {@inheritdoc} */ - public function getMaxIdentifierLength() + public function getMaxIdentifierLength() : int { return 128; } @@ -993,15 +957,23 @@ public function getMaxIdentifierLength() /** * {@inheritdoc} */ - public function getMd5Expression($column) + public function getMd5Expression(string $string) : string { - return 'HASH(' . $column . ", 'MD5')"; + return 'HASH(' . $string . ", 'MD5')"; } /** * {@inheritdoc} */ - public function getName() + public function getRegexpExpression() : string + { + return 'REGEXP'; + } + + /** + * {@inheritdoc} + */ + public function getName() : string { return 'sqlanywhere'; } @@ -1017,7 +989,7 @@ public function getName() * * @throws InvalidArgumentException If the given index is not a primary key. */ - public function getPrimaryKeyDeclarationSQL(Index $index, $name = null) + public function getPrimaryKeyDeclarationSQL(Index $index, ?string $name = null) : string { if (! $index->isPrimary()) { throw new InvalidArgumentException( @@ -1031,7 +1003,7 @@ public function getPrimaryKeyDeclarationSQL(Index $index, $name = null) /** * {@inheritdoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level); } @@ -1039,7 +1011,7 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritdoc} */ - public function getSmallIntTypeDeclarationSQL(array $columnDef) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { $columnDef['integer_type'] = 'SMALLINT'; @@ -1056,10 +1028,8 @@ public function getSmallIntTypeDeclarationSQL(array $columnDef) * SQL Anywhere does not automatically start a database after creation! * * @param string $database Name of the database to start. - * - * @return string */ - public function getStartDatabaseSQL($database) + public function getStartDatabaseSQL(string $database) : string { $database = new Identifier($database); @@ -1075,10 +1045,8 @@ public function getStartDatabaseSQL($database) * as it has to be explicitly stopped before it can be dropped. * * @param string $database Name of the database to stop. - * - * @return string */ - public function getStopDatabaseSQL($database) + public function getStopDatabaseSQL(string $database) : string { $database = new Identifier($database); @@ -1088,19 +1056,19 @@ public function getStopDatabaseSQL($database) /** * {@inheritdoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { if ($length === null) { - return 'SUBSTRING(' . $value . ', ' . $from . ')'; + return sprintf('SUBSTRING(%s, %s)', $string, $start); } - return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; + return sprintf('SUBSTRING(%s, %s, %s)', $string, $start, $length); } /** * {@inheritdoc} */ - public function getTemporaryTableSQL() + public function getTemporaryTableSQL() : string { return 'GLOBAL TEMPORARY'; } @@ -1108,7 +1076,7 @@ public function getTemporaryTableSQL() /** * {@inheritdoc} */ - public function getTimeFormatString() + public function getTimeFormatString() : string { return 'H:i:s.u'; } @@ -1116,7 +1084,7 @@ public function getTimeFormatString() /** * {@inheritdoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIME'; } @@ -1124,10 +1092,16 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritdoc} */ - public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - if (! $char) { - switch ($pos) { + if (! in_array($mode, [TrimMode::UNSPECIFIED, TrimMode::LEADING, TrimMode::TRAILING, TrimMode::BOTH], true)) { + throw new InvalidArgumentException( + sprintf('The value of $mode is expected to be one of the TrimMode constants, %d given', $mode) + ); + } + + if ($char === null) { + switch ($mode) { case TrimMode::LEADING: return $this->getLtrimExpression($str); case TrimMode::TRAILING: @@ -1139,7 +1113,7 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa $pattern = "'%[^' + " . $char . " + ']%'"; - switch ($pos) { + switch ($mode) { case TrimMode::LEADING: return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))'; case TrimMode::TRAILING: @@ -1153,7 +1127,7 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa /** * {@inheritdoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); @@ -1163,44 +1137,55 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * {@inheritdoc} */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) + public function getCreateSequenceSQL(Sequence $sequence) : string { - if ($index->isPrimary()) { - throw new InvalidArgumentException( - 'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().' - ); - } + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue(); + } - if (! $index->isUnique()) { - throw new InvalidArgumentException( - 'Can only create unique constraint declarations, no common index declarations with ' . - 'getUniqueConstraintDeclarationSQL().' - ); + /** + * {@inheritdoc} + */ + public function getAlterSequenceSQL(Sequence $sequence) : string + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritdoc} + */ + public function getDropSequenceSQL($sequence) : string + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); } - return $this->getTableConstraintDeclarationSQL($index, $name); + return 'DROP SEQUENCE ' . $sequence; } /** * {@inheritdoc} */ - public function getVarcharDefaultLength() + public function getListSequencesSQL(string $database) : string { - return 1; + return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; } /** * {@inheritdoc} */ - public function getVarcharMaxLength() + public function getSequenceNextValSQL(string $sequenceName) : string { - return 32767; + return 'SELECT ' . $sequenceName . '.NEXTVAL'; } /** * {@inheritdoc} */ - public function hasNativeGuidType() + public function supportsSequences() : bool { return true; } @@ -1208,7 +1193,15 @@ public function hasNativeGuidType() /** * {@inheritdoc} */ - public function prefersIdentityColumns() + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) : string + { + return 'TIMESTAMP WITH TIME ZONE'; + } + + /** + * {@inheritdoc} + */ + public function hasNativeGuidType() : bool { return true; } @@ -1216,7 +1209,7 @@ public function prefersIdentityColumns() /** * {@inheritdoc} */ - public function supportsCommentOnStatement() + public function prefersIdentityColumns() : bool { return true; } @@ -1224,7 +1217,7 @@ public function supportsCommentOnStatement() /** * {@inheritdoc} */ - public function supportsIdentityColumns() + public function supportsCommentOnStatement() : bool { return true; } @@ -1232,7 +1225,15 @@ public function supportsIdentityColumns() /** * {@inheritdoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + public function supportsIdentityColumns() : bool + { + return true; + } + + /** + * {@inheritdoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { $unsigned = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : ''; $autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : ''; @@ -1243,7 +1244,7 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritdoc} */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $columnListSql = $this->getColumnDeclarationListSQL($columns); $indexSql = []; @@ -1292,26 +1293,26 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options /** * {@inheritdoc} */ - protected function _getTransactionIsolationLevelSQL($level) + protected function _getTransactionIsolationLevelSQL(int $level) : string { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: - return 0; + return '0'; case TransactionIsolationLevel::READ_COMMITTED: - return 1; + return '1'; case TransactionIsolationLevel::REPEATABLE_READ: - return 2; + return '2'; case TransactionIsolationLevel::SERIALIZABLE: - return 3; + return '3'; default: - throw new InvalidArgumentException('Invalid isolation level:' . $level); + throw new InvalidArgumentException(sprintf('Invalid isolation level %d.', $level)); } } /** * {@inheritdoc} */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $limitOffsetClause = $this->getTopClauseSQL($limit, $offset); @@ -1340,28 +1341,30 @@ private function getTopClauseSQL(?int $limit, ?int $offset) : string * SQL Anywhere options. * * @param Index $index Index definition - * - * @return string */ - protected function getAdvancedIndexOptionsSQL(Index $index) + protected function getAdvancedIndexOptionsSQL(Index $index) : string { + if ($index->hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { + throw new UnexpectedValueException( + 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' + ); + } + $sql = ''; if (! $index->isPrimary() && $index->hasFlag('for_olap_workload')) { $sql .= ' FOR OLAP WORKLOAD'; } - return $sql; - } + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { + return ' WITH NULLS NOT DISTINCT' . $sql; + } - /** - * {@inheritdoc} - */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) - { - return $fixed - ? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')' - : 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'; + if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { + return ' WITH NULLS DISTINCT' . $sql; + } + + return $sql; } /** @@ -1370,18 +1373,16 @@ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) * @param Constraint $constraint The table constraint to create the SQL snippet for. * @param string|null $name The table constraint name to use if any. * - * @return string - * * @throws InvalidArgumentException If the given table constraint type is not supported by this method. */ - protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null) + protected function getTableConstraintDeclarationSQL(Constraint $constraint, ?string $name = null) : string { if ($constraint instanceof ForeignKeyConstraint) { return $this->getForeignKeyDeclarationSQL($constraint); } if (! $constraint instanceof Index) { - throw new InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint)); + throw new InvalidArgumentException(sprintf('Unsupported constraint type %s.', get_class($constraint))); } if (! $constraint->isPrimary() && ! $constraint->isUnique()) { @@ -1394,7 +1395,7 @@ protected function getTableConstraintDeclarationSQL(Constraint $constraint, $nam $constraintColumns = $constraint->getQuotedColumns($this); if (empty($constraintColumns)) { - throw new InvalidArgumentException("Incomplete definition. 'columns' required."); + throw new InvalidArgumentException('Incomplete definition. "columns" required.'); } $sql = ''; @@ -1419,7 +1420,7 @@ protected function getTableConstraintDeclarationSQL(Constraint $constraint, $nam /** * {@inheritdoc} */ - protected function getCreateIndexSQLFlags(Index $index) + protected function getCreateIndexSQLFlags(Index $index) : string { $type = ''; if ($index->hasFlag('virtual')) { @@ -1440,7 +1441,7 @@ protected function getCreateIndexSQLFlags(Index $index) /** * {@inheritdoc} */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { return ['ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)]; } @@ -1448,7 +1449,7 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) /** * {@inheritdoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\SQLAnywhereKeywords::class; } @@ -1456,57 +1457,48 @@ protected function getReservedKeywordsClass() /** * {@inheritdoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) - { - return $fixed - ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')') - : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')'); - } - - /** - * {@inheritdoc} - */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'char' => 'string', - 'long nvarchar' => 'text', - 'long varchar' => 'text', - 'nchar' => 'string', - 'ntext' => 'text', - 'nvarchar' => 'string', - 'text' => 'text', - 'uniqueidentifierstr' => 'guid', - 'varchar' => 'string', - 'xml' => 'text', - 'bigint' => 'bigint', - 'unsigned bigint' => 'bigint', - 'bit' => 'boolean', - 'decimal' => 'decimal', - 'double' => 'float', - 'float' => 'float', - 'int' => 'integer', - 'integer' => 'integer', - 'unsigned int' => 'integer', - 'numeric' => 'decimal', - 'smallint' => 'smallint', - 'unsigned smallint' => 'smallint', - 'tinyint' => 'smallint', - 'unsigned tinyint' => 'smallint', - 'money' => 'decimal', - 'smallmoney' => 'decimal', - 'long varbit' => 'text', - 'varbit' => 'string', - 'date' => 'date', - 'datetime' => 'datetime', - 'smalldatetime' => 'datetime', - 'time' => 'time', - 'timestamp' => 'datetime', - 'binary' => 'binary', - 'image' => 'blob', - 'long binary' => 'blob', - 'uniqueidentifier' => 'guid', - 'varbinary' => 'binary', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'bit' => 'boolean', + 'char' => 'string', + 'decimal' => 'decimal', + 'date' => 'date', + 'datetime' => 'datetime', + 'double' => 'float', + 'float' => 'float', + 'image' => 'blob', + 'int' => 'integer', + 'integer' => 'integer', + 'long binary' => 'blob', + 'long nvarchar' => 'text', + 'long varbit' => 'text', + 'long varchar' => 'text', + 'money' => 'decimal', + 'nchar' => 'string', + 'ntext' => 'text', + 'numeric' => 'decimal', + 'nvarchar' => 'string', + 'smalldatetime' => 'datetime', + 'smallint' => 'smallint', + 'smallmoney' => 'decimal', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'timestamp with time zone' => 'datetime', + 'tinyint' => 'smallint', + 'uniqueidentifier' => 'guid', + 'uniqueidentifierstr' => 'guid', + 'unsigned bigint' => 'bigint', + 'unsigned int' => 'integer', + 'unsigned smallint' => 'smallint', + 'unsigned tinyint' => 'smallint', + 'varbinary' => 'binary', + 'varbit' => 'string', + 'varchar' => 'string', + 'xml' => 'text', ]; } } diff --git a/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php b/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php index a104848f84e..e3ed527b619 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php @@ -1,5 +1,7 @@ doctrineTypeMapping['datetime2'] = 'datetime'; - $this->doctrineTypeMapping['date'] = 'date'; - $this->doctrineTypeMapping['time'] = 'time'; - $this->doctrineTypeMapping['datetimeoffset'] = 'datetimetz'; - } - - /** - * {@inheritdoc} - * - * Returns Microsoft SQL Server 2008 specific keywords class - */ - protected function getReservedKeywordsClass() - { - return Keywords\SQLServer2008Keywords::class; - } - - protected function getLikeWildcardCharacters() : string - { - return parent::getLikeWildcardCharacters() . '[]^'; - } -} diff --git a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php index 009a37d33b0..8bd564383b7 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php @@ -1,11 +1,14 @@ getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize(); @@ -28,7 +31,7 @@ public function getAlterSequenceSQL(Sequence $sequence) /** * {@inheritdoc} */ - public function getCreateSequenceSQL(Sequence $sequence) + public function getCreateSequenceSQL(Sequence $sequence) : string { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' START WITH ' . $sequence->getInitialValue() . @@ -39,7 +42,7 @@ public function getCreateSequenceSQL(Sequence $sequence) /** * {@inheritdoc} */ - public function getDropSequenceSQL($sequence) + public function getDropSequenceSQL($sequence) : string { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); @@ -51,7 +54,7 @@ public function getDropSequenceSQL($sequence) /** * {@inheritdoc} */ - public function getListSequencesSQL($database) + public function getListSequencesSQL(string $database) : string { return 'SELECT seq.name, CAST( @@ -66,7 +69,7 @@ public function getListSequencesSQL($database) /** * {@inheritdoc} */ - public function getSequenceNextValSQL($sequenceName) + public function getSequenceNextValSQL(string $sequenceName) : string { return 'SELECT NEXT VALUE FOR ' . $sequenceName; } @@ -74,7 +77,7 @@ public function getSequenceNextValSQL($sequenceName) /** * {@inheritdoc} */ - public function supportsSequences() + public function supportsSequences() : bool { return true; } @@ -84,7 +87,7 @@ public function supportsSequences() * * Returns Microsoft SQL Server 2012 specific keywords class */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\SQLServer2012Keywords::class; } @@ -92,7 +95,7 @@ protected function getReservedKeywordsClass() /** * {@inheritdoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset <= 0) { return $query; @@ -125,17 +128,13 @@ protected function doModifyLimitQuery($query, $limit, $offset = null) } } - if ($offset === null) { - $offset = 0; - } - // This looks somewhat like MYSQL, but limit/offset are in inverse positions // Supposedly SQL:2008 core standard. // Per TSQL spec, FETCH NEXT n ROWS ONLY is not valid without OFFSET n ROWS. - $query .= ' OFFSET ' . (int) $offset . ' ROWS'; + $query .= sprintf(' OFFSET %d ROWS', $offset); if ($limit !== null) { - $query .= ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; + $query .= sprintf(' FETCH NEXT %d ROWS ONLY', $limit); } return $query; diff --git a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php index 3258a6623ad..55be1a273dd 100644 --- a/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -1,7 +1,10 @@ getConvertExpression('date', 'GETDATE()'); } @@ -52,7 +55,7 @@ public function getCurrentDateSQL() /** * {@inheritdoc} */ - public function getCurrentTimeSQL() + public function getCurrentTimeSQL() : string { return $this->getConvertExpression('time', 'GETDATE()'); } @@ -62,10 +65,8 @@ public function getCurrentTimeSQL() * * @param string $dataType The target native data type. Alias data types cannot be used. * @param string $expression The SQL expression to convert. - * - * @return string */ - private function getConvertExpression($dataType, $expression) + private function getConvertExpression(string $dataType, string $expression) : string { return sprintf('CONVERT(%s, %s)', $dataType, $expression); } @@ -73,7 +74,7 @@ private function getConvertExpression($dataType, $expression) /** * {@inheritdoc} */ - protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) + protected function getDateArithmeticIntervalExpression(string $date, string $operator, string $interval, string $unit) : string { $factorClause = ''; @@ -87,7 +88,7 @@ protected function getDateArithmeticIntervalExpression($date, $operator, $interv /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')'; } @@ -98,7 +99,7 @@ public function getDateDiffExpression($date1, $date2) * Microsoft SQL Server prefers "autoincrement" identity columns * since sequences can only be emulated with a table. */ - public function prefersIdentityColumns() + public function prefersIdentityColumns() : bool { return true; } @@ -108,7 +109,7 @@ public function prefersIdentityColumns() * * Microsoft SQL Server supports this through AUTO_INCREMENT columns. */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return true; } @@ -116,7 +117,7 @@ public function supportsIdentityColumns() /** * {@inheritDoc} */ - public function supportsReleaseSavepoints() + public function supportsReleaseSavepoints() : bool { return false; } @@ -124,7 +125,7 @@ public function supportsReleaseSavepoints() /** * {@inheritdoc} */ - public function supportsSchemas() + public function supportsSchemas() : bool { return true; } @@ -132,7 +133,7 @@ public function supportsSchemas() /** * {@inheritdoc} */ - public function getDefaultSchemaName() + public function getDefaultSchemaName() : string { return 'dbo'; } @@ -140,7 +141,7 @@ public function getDefaultSchemaName() /** * {@inheritDoc} */ - public function supportsColumnCollation() + public function supportsColumnCollation() : bool { return true; } @@ -148,7 +149,7 @@ public function supportsColumnCollation() /** * {@inheritDoc} */ - public function hasNativeGuidType() + public function hasNativeGuidType() : bool { return true; } @@ -156,23 +157,23 @@ public function hasNativeGuidType() /** * {@inheritDoc} */ - public function getCreateDatabaseSQL($name) + public function getCreateDatabaseSQL(string $database) : string { - return 'CREATE DATABASE ' . $name; + return 'CREATE DATABASE ' . $database; } /** * {@inheritDoc} */ - public function getDropDatabaseSQL($name) + public function getDropDatabaseSQL(string $database) : string { - return 'DROP DATABASE ' . $name; + return 'DROP DATABASE ' . $database; } /** * {@inheritDoc} */ - public function supportsCreateDropDatabase() + public function supportsCreateDropDatabase() : bool { return true; } @@ -180,7 +181,7 @@ public function supportsCreateDropDatabase() /** * {@inheritDoc} */ - public function getCreateSchemaSQL($schemaName) + public function getCreateSchemaSQL(string $schemaName) : string { return 'CREATE SCHEMA ' . $schemaName; } @@ -188,7 +189,7 @@ public function getCreateSchemaSQL($schemaName) /** * {@inheritDoc} */ - public function getDropForeignKeySQL($foreignKey, $table) + public function getDropForeignKeySQL($foreignKey, $table) : string { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); @@ -207,12 +208,15 @@ public function getDropForeignKeySQL($foreignKey, $table) /** * {@inheritDoc} */ - public function getDropIndexSQL($index, $table = null) + public function getDropIndexSQL($index, $table = null) : string { if ($index instanceof Index) { $index = $index->getQuotedName($this); } elseif (! is_string($index)) { - throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + throw new InvalidArgumentException(sprintf( + 'AbstractPlatform::getDropIndexSQL() expects $index parameter to be a string or an instanceof %s.', + Index::class + )); } if (! isset($table)) { @@ -242,7 +246,7 @@ public function getDropIndexSQL($index, $table = null) /** * {@inheritDoc} */ - protected function _getCreateTableSQL($tableName, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { $defaultConstraintsSql = []; $commentsSql = []; @@ -311,7 +315,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options /** * {@inheritDoc} */ - public function getCreatePrimaryKeySQL(Index $index, $table) + public function getCreatePrimaryKeySQL(Index $index, $table) : string { if ($table instanceof Table) { $identifier = $table->getQuotedName($this); @@ -342,10 +346,8 @@ public function getCreatePrimaryKeySQL(Index $index, $table) * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to create the comment for. * @param string|null $comment The column's comment. - * - * @return string */ - protected function getCreateColumnCommentSQL($tableName, $columnName, $comment) + protected function getCreateColumnCommentSQL(string $tableName, string $columnName, ?string $comment) : string { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); @@ -374,14 +376,12 @@ protected function getCreateColumnCommentSQL($tableName, $columnName, $comment) * @param string $table Name of the table to return the default constraint declaration for. * @param mixed[] $column Column definition. * - * @return string - * * @throws InvalidArgumentException */ - public function getDefaultConstraintDeclarationSQL($table, array $column) + public function getDefaultConstraintDeclarationSQL(string $table, array $column) : string { if (! isset($column['default'])) { - throw new InvalidArgumentException("Incomplete column definition. 'default' required."); + throw new InvalidArgumentException('Incomplete column definition. "default" required.'); } $columnName = new Identifier($column['name']); @@ -395,19 +395,7 @@ public function getDefaultConstraintDeclarationSQL($table, array $column) /** * {@inheritDoc} */ - public function getUniqueConstraintDeclarationSQL($name, Index $index) - { - $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index); - - $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); - - return $constraint; - } - - /** - * {@inheritDoc} - */ - public function getCreateIndexSQL(Index $index, $table) + public function getCreateIndexSQL(Index $index, $table) : string { $constraint = parent::getCreateIndexSQL($index, $table); @@ -421,7 +409,7 @@ public function getCreateIndexSQL(Index $index, $table) /** * {@inheritDoc} */ - protected function getCreateIndexSQLFlags(Index $index) + protected function getCreateIndexSQLFlags(Index $index) : string { $type = ''; if ($index->isUnique()) { @@ -439,12 +427,8 @@ protected function getCreateIndexSQLFlags(Index $index) /** * Extend unique key constraint with required filters - * - * @param string $sql - * - * @return string */ - private function _appendUniqueConstraintDefinition($sql, Index $index) + private function _appendUniqueConstraintDefinition(string $sql, Index $index) : string { $fields = []; @@ -458,7 +442,7 @@ private function _appendUniqueConstraintDefinition($sql, Index $index) /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $queryParts = []; $sql = []; @@ -591,7 +575,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = "sp_RENAME '" . $diff->getName($this)->getQuotedName($this) . "', '" . $newName->getName() . "'"; /** @@ -626,10 +610,8 @@ public function getAlterTableSQL(TableDiff $diff) * * @param string $tableName The name of the table to generate the clause for. * @param Column $column The column to generate the clause for. - * - * @return string */ - private function getAlterTableAddDefaultConstraintClause($tableName, Column $column) + private function getAlterTableAddDefaultConstraintClause(string $tableName, Column $column) : string { $columnDef = $column->toArray(); $columnDef['name'] = $column->getQuotedName($this); @@ -642,10 +624,8 @@ private function getAlterTableAddDefaultConstraintClause($tableName, Column $col * * @param string $tableName The name of the table to generate the clause for. * @param string $columnName The name of the column to generate the clause for. - * - * @return string */ - private function getAlterTableDropDefaultConstraintClause($tableName, $columnName) + private function getAlterTableDropDefaultConstraintClause(string $tableName, string $columnName) : string { return 'DROP CONSTRAINT ' . $this->generateDefaultConstraintName($tableName, $columnName); } @@ -662,7 +642,7 @@ private function getAlterTableDropDefaultConstraintClause($tableName, $columnNam * * @return bool True if the column alteration requires dropping its default constraint first, false otherwise. */ - private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff) + private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff) : bool { // We can only decide whether to drop an existing default constraint // if we know the original default value. @@ -701,10 +681,8 @@ private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to alter the comment for. * @param string|null $comment The column's comment. - * - * @return string */ - protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) + protected function getAlterColumnCommentSQL(string $tableName, string $columnName, ?string $comment) : string { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); @@ -740,10 +718,8 @@ protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) * * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to drop the comment for. - * - * @return string */ - protected function getDropColumnCommentSQL($tableName, $columnName) + protected function getDropColumnCommentSQL(string $tableName, string $columnName) : string { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); @@ -768,7 +744,7 @@ protected function getDropColumnCommentSQL($tableName, $columnName) /** * {@inheritdoc} */ - protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) + protected function getRenameIndexSQL(string $oldIndexName, Index $index, string $tableName) : array { return [sprintf( "EXEC sp_RENAME N'%s.%s', N'%s', N'INDEX'", @@ -792,19 +768,17 @@ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. - * - * @return string */ public function getAddExtendedPropertySQL( - $name, - $value = null, - $level0Type = null, - $level0Name = null, - $level1Type = null, - $level1Name = null, - $level2Type = null, - $level2Name = null - ) { + string $name, + ?string $value = null, + ?string $level0Type = null, + ?string $level0Name = null, + ?string $level1Type = null, + ?string $level1Name = null, + ?string $level2Type = null, + ?string $level2Name = null + ) : string { return 'EXEC sp_addextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . @@ -824,18 +798,16 @@ public function getAddExtendedPropertySQL( * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. - * - * @return string */ public function getDropExtendedPropertySQL( - $name, - $level0Type = null, - $level0Name = null, - $level1Type = null, - $level1Name = null, - $level2Type = null, - $level2Name = null - ) { + string $name, + ?string $level0Type = null, + ?string $level0Name = null, + ?string $level1Type = null, + ?string $level1Name = null, + ?string $level2Type = null, + ?string $level2Name = null + ) : string { return 'EXEC sp_dropextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . @@ -856,19 +828,17 @@ public function getDropExtendedPropertySQL( * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. - * - * @return string */ public function getUpdateExtendedPropertySQL( - $name, - $value = null, - $level0Type = null, - $level0Name = null, - $level1Type = null, - $level1Name = null, - $level2Type = null, - $level2Name = null - ) { + string $name, + ?string $value = null, + ?string $level0Type = null, + ?string $level0Name = null, + ?string $level1Type = null, + ?string $level1Name = null, + ?string $level2Type = null, + ?string $level2Name = null + ) : string { return 'EXEC sp_updateextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . @@ -879,25 +849,25 @@ public function getUpdateExtendedPropertySQL( /** * {@inheritDoc} */ - public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + public function getEmptyIdentityInsertSQL(string $tableName, string $identifierColumnName) : string { - return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; + return 'INSERT INTO ' . $tableName . ' DEFAULT VALUES'; } /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams // Category 2 must be ignored as it is "MS SQL Server 'pseudo-system' object[s]" for replication - return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; + return "SELECT name, SCHEMA_NAME (uid) AS schema_name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; } /** * {@inheritDoc} */ - public function getListTableColumnsSQL($table, $database = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { return "SELECT col.name, type.name AS type, @@ -930,7 +900,7 @@ public function getListTableColumnsSQL($table, $database = null) /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table, $database = null) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { return 'SELECT f.name AS ForeignKey, SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName, @@ -952,7 +922,7 @@ public function getListTableForeignKeysSQL($table, $database = null) /** * {@inheritDoc} */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { return "SELECT idx.name AS key_name, col.name AS column_name, @@ -975,7 +945,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -983,7 +953,7 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name"; } @@ -994,10 +964,8 @@ public function getListViewsSQL($database) * @param string $table The full qualified name of the table. * @param string $schemaColumn The name of the column to compare the schema to in the where clause. * @param string $tableColumn The name of the column to compare the table to in the where clause. - * - * @return string */ - private function getTableWhereClause($table, $schemaColumn, $tableColumn) + private function getTableWhereClause(string $table, string $schemaColumn, string $tableColumn) : string { if (strpos($table, '.') !== false) { [$schema, $table] = explode('.', $table); @@ -1014,61 +982,53 @@ private function getTableWhereClause($table, $schemaColumn, $tableColumn) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } - /** - * {@inheritDoc} - * - * @deprecated Use application-generated UUIDs instead - */ - public function getGuidExpression() - { - return 'NEWID()'; - } - /** * {@inheritDoc} */ - public function getLocateExpression($str, $substr, $startPos = false) + public function getLocateExpression(string $string, string $substring, ?string $start = null) : string { - if ($startPos === false) { - return 'CHARINDEX(' . $substr . ', ' . $str . ')'; + if ($start === null) { + return sprintf('CHARINDEX(%s, %s)', $substring, $string); } - return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + return sprintf('CHARINDEX(%s, %s, %s)', $substring, $string, $start); } /** * {@inheritDoc} */ - public function getModExpression($expression1, $expression2) + public function getModExpression(string $dividend, string $divisor) : string { - return $expression1 . ' % ' . $expression2; + return $dividend . ' % ' . $divisor; } /** * {@inheritDoc} */ - public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) + public function getTrimExpression(string $str, int $mode = TrimMode::UNSPECIFIED, ?string $char = null) : string { - if (! $char) { - switch ($pos) { + if (! in_array($mode, [TrimMode::UNSPECIFIED, TrimMode::LEADING, TrimMode::TRAILING, TrimMode::BOTH], true)) { + throw new InvalidArgumentException( + sprintf('The value of $mode is expected to be one of the TrimMode constants, %d given', $mode) + ); + } + + if ($char === null) { + switch ($mode) { case TrimMode::LEADING: - $trimFn = 'LTRIM'; - break; + return 'LTRIM(' . $str . ')'; case TrimMode::TRAILING: - $trimFn = 'RTRIM'; - break; + return 'RTRIM(' . $str . ')'; default: return 'LTRIM(RTRIM(' . $str . '))'; } - - return $trimFn . '(' . $str . ')'; } /** Original query used to get those expressions @@ -1082,11 +1042,11 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa */ $pattern = "'%[^' + " . $char . " + ']%'"; - if ($pos === TrimMode::LEADING) { + if ($mode === TrimMode::LEADING) { return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)'; } - if ($pos === TrimMode::TRAILING) { + if ($mode === TrimMode::TRAILING) { return 'reverse(stuff(reverse(' . $str . '), 1, patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))'; } @@ -1096,17 +1056,15 @@ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = fa /** * {@inheritDoc} */ - public function getConcatExpression() + public function getConcatExpression(string ...$string) : string { - $args = func_get_args(); - - return '(' . implode(' + ', $args) . ')'; + return '(' . implode(' + ', $string) . ')'; } /** * {@inheritDoc} */ - public function getListDatabasesSQL() + public function getListDatabasesSQL() : string { return 'SELECT * FROM sys.databases'; } @@ -1114,7 +1072,7 @@ public function getListDatabasesSQL() /** * {@inheritDoc} */ - public function getListNamespacesSQL() + public function getListNamespacesSQL() : string { return "SELECT name FROM sys.schemas WHERE name NOT IN('guest', 'INFORMATION_SCHEMA', 'sys')"; } @@ -1122,27 +1080,27 @@ public function getListNamespacesSQL() /** * {@inheritDoc} */ - public function getSubstringExpression($value, $from, $length = null) + public function getSubstringExpression(string $string, string $start, ?string $length = null) : string { - if ($length !== null) { - return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; + if ($length === null) { + return sprintf('SUBSTRING(%s, %s, LEN(%s) - %s + 1)', $string, $start, $string, $start); } - return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)'; + return sprintf('SUBSTRING(%s, %s, %s)', $string, $start, $length); } /** * {@inheritDoc} */ - public function getLengthExpression($column) + public function getLengthExpression(string $string) : string { - return 'LEN(' . $column . ')'; + return 'LEN(' . $string . ')'; } /** * {@inheritDoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } @@ -1150,31 +1108,31 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { - return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { - return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { - return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getGuidTypeDeclarationSQL(array $field) + public function getGuidTypeDeclarationSQL(array $column) : string { return 'UNIQUEIDENTIFIER'; } @@ -1182,31 +1140,41 @@ public function getGuidTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) : string { - return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NVARCHAR(255)'); + return 'DATETIMEOFFSET(6)'; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getCharTypeDeclarationSQLSnippet(?int $length) : string { - return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; + $sql = 'NCHAR'; + + if ($length !== null) { + $sql .= sprintf('(%d)', $length); + } + + return $sql; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getBinaryMaxLength() + protected function getVarcharTypeDeclarationSQLSnippet(?int $length) : string { - return 8000; + if ($length === null) { + throw ColumnLengthRequired::new($this, 'NVARCHAR'); + } + + return sprintf('NVARCHAR(%d)', $length); } /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { return 'VARCHAR(MAX)'; } @@ -1214,7 +1182,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { return ! empty($columnDef['autoincrement']) ? ' IDENTITY' : ''; } @@ -1222,31 +1190,33 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { - return 'DATETIME'; + // 3 - microseconds precision length + // http://msdn.microsoft.com/en-us/library/ms187819.aspx + return 'DATETIME2(6)'; } /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { - return 'DATETIME'; + return 'DATE'; } /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { - return 'DATETIME'; + return 'TIME(0)'; } /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'BIT'; } @@ -1254,7 +1224,7 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset = null) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { $where = []; @@ -1304,12 +1274,8 @@ protected function doModifyLimitQuery($query, $limit, $offset = null) /** * Remove ORDER BY clauses in subqueries - they're not supported by SQL Server. * Caveat: will leave ORDER BY in TOP N subqueries. - * - * @param string $query - * - * @return string */ - private function scrubInnerOrderBy($query) + private function scrubInnerOrderBy(string $query) : string { $count = substr_count(strtoupper($query), 'ORDER BY'); $offset = 0; @@ -1360,7 +1326,7 @@ private function scrubInnerOrderBy($query) * * @return bool true if ORDER BY is in a TOP N query, false otherwise */ - private function isOrderByInTopNSubquery($query, $currentPosition) + private function isOrderByInTopNSubquery(string $query, int $currentPosition) : bool { // Grab query text on the same nesting level as the ORDER BY clause we're examining. $subQueryBuffer = ''; @@ -1387,9 +1353,9 @@ private function isOrderByInTopNSubquery($query, $currentPosition) /** * {@inheritDoc} */ - public function supportsLimitOffset() + public function supportsLimitOffset() : bool { - return false; + return true; } /** @@ -1415,7 +1381,7 @@ public function convertBooleans($item) /** * {@inheritDoc} */ - public function getCreateTemporaryTableSnippetSQL() + public function getCreateTemporaryTableSnippetSQL() : string { return 'CREATE TABLE'; } @@ -1423,7 +1389,7 @@ public function getCreateTemporaryTableSnippetSQL() /** * {@inheritDoc} */ - public function getTemporaryTableName($tableName) + public function getTemporaryTableName(string $tableName) : string { return '#' . $tableName; } @@ -1431,39 +1397,39 @@ public function getTemporaryTableName($tableName) /** * {@inheritDoc} */ - public function getDateTimeFormatString() + public function getDateTimeFormatString() : string { - return 'Y-m-d H:i:s.000'; + return 'Y-m-d H:i:s.u'; } /** * {@inheritDoc} */ - public function getDateFormatString() + public function getDateFormatString() : string { - return 'Y-m-d H:i:s.000'; + return 'Y-m-d'; } /** * {@inheritDoc} */ - public function getTimeFormatString() + public function getTimeFormatString() : string { - return 'Y-m-d H:i:s.000'; + return 'H:i:s'; } /** * {@inheritDoc} */ - public function getDateTimeTzFormatString() + public function getDateTimeTzFormatString() : string { - return $this->getDateTimeFormatString(); + return 'Y-m-d H:i:s.u P'; } /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'mssql'; } @@ -1471,41 +1437,45 @@ public function getName() /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'bigint' => 'bigint', - 'numeric' => 'decimal', - 'bit' => 'boolean', - 'smallint' => 'smallint', - 'decimal' => 'decimal', - 'smallmoney' => 'integer', - 'int' => 'integer', - 'tinyint' => 'smallint', - 'money' => 'integer', - 'float' => 'float', - 'real' => 'float', - 'double' => 'float', + 'bigint' => 'bigint', + 'binary' => 'binary', + 'bit' => 'boolean', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'datetime2' => 'datetime', + 'datetimeoffset' => 'datetimetz', + 'decimal' => 'decimal', + 'double' => 'float', 'double precision' => 'float', - 'smalldatetime' => 'datetime', - 'datetime' => 'datetime', - 'char' => 'string', - 'varchar' => 'string', - 'text' => 'text', - 'nchar' => 'string', - 'nvarchar' => 'string', - 'ntext' => 'text', - 'binary' => 'binary', - 'varbinary' => 'binary', - 'image' => 'blob', + 'float' => 'float', + 'image' => 'blob', + 'int' => 'integer', + 'money' => 'integer', + 'nchar' => 'string', + 'ntext' => 'text', + 'numeric' => 'decimal', + 'nvarchar' => 'string', + 'real' => 'float', + 'smalldatetime' => 'datetime', + 'smallint' => 'smallint', + 'smallmoney' => 'integer', + 'text' => 'text', + 'time' => 'time', + 'tinyint' => 'smallint', 'uniqueidentifier' => 'guid', + 'varbinary' => 'binary', + 'varchar' => 'string', ]; } /** * {@inheritDoc} */ - public function createSavePoint($savepoint) + public function createSavePoint(string $savepoint) : string { return 'SAVE TRANSACTION ' . $savepoint; } @@ -1513,7 +1483,7 @@ public function createSavePoint($savepoint) /** * {@inheritDoc} */ - public function releaseSavePoint($savepoint) + public function releaseSavePoint(string $savepoint) : string { return ''; } @@ -1521,7 +1491,7 @@ public function releaseSavePoint($savepoint) /** * {@inheritDoc} */ - public function rollbackSavePoint($savepoint) + public function rollbackSavePoint(string $savepoint) : string { return 'ROLLBACK TRANSACTION ' . $savepoint; } @@ -1529,7 +1499,7 @@ public function rollbackSavePoint($savepoint) /** * {@inheritdoc} */ - public function getForeignKeyReferentialActionSQL($action) + public function getForeignKeyReferentialActionSQL(string $action) : string { // RESTRICT is not supported, therefore falling back to NO ACTION. if (strtoupper($action) === 'RESTRICT') { @@ -1542,7 +1512,7 @@ public function getForeignKeyReferentialActionSQL($action) /** * {@inheritDoc} */ - public function appendLockHint($fromClause, $lockMode) + public function appendLockHint(string $fromClause, ?int $lockMode) : string { switch (true) { case $lockMode === LockMode::NONE: @@ -1562,7 +1532,7 @@ public function appendLockHint($fromClause, $lockMode) /** * {@inheritDoc} */ - public function getForUpdateSQL() + public function getForUpdateSQL() : string { return ' '; } @@ -1570,7 +1540,7 @@ public function getForUpdateSQL() /** * {@inheritDoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\SQLServerKeywords::class; } @@ -1578,7 +1548,7 @@ protected function getReservedKeywordsClass() /** * {@inheritDoc} */ - public function quoteSingleIdentifier($str) + public function quoteSingleIdentifier(string $str) : string { return '[' . str_replace(']', '][', $str) . ']'; } @@ -1586,7 +1556,7 @@ public function quoteSingleIdentifier($str) /** * {@inheritDoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); @@ -1596,7 +1566,7 @@ public function getTruncateTableSQL($tableName, $cascade = false) /** * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { return 'VARBINARY(MAX)'; } @@ -1606,7 +1576,7 @@ public function getBlobTypeDeclarationSQL(array $field) * * Modifies column declaration order as it differs in Microsoft SQL Server. */ - public function getColumnDeclarationSQL($name, array $field) + public function getColumnDeclarationSQL(string $name, array $field) : string { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); @@ -1629,15 +1599,21 @@ public function getColumnDeclarationSQL($name, array $field) return $name . ' ' . $columnDef; } + /** + * {@inheritdoc} + */ + protected function getLikeWildcardCharacters() : string + { + return parent::getLikeWildcardCharacters() . '[]^'; + } + /** * Returns a unique default constraint name for a table and column. * * @param string $table Name of the table to generate the unique default constraint name for. * @param string $column Name of the column in the table to generate the unique default constraint name for. - * - * @return string */ - private function generateDefaultConstraintName($table, $column) + private function generateDefaultConstraintName(string $table, string $column) : string { return 'DF_' . $this->generateIdentifierName($table) . '_' . $this->generateIdentifierName($column); } @@ -1646,10 +1622,8 @@ private function generateDefaultConstraintName($table, $column) * Returns a hash value for a given identifier. * * @param string $identifier Identifier to generate a hash value for. - * - * @return string */ - private function generateIdentifierName($identifier) + private function generateIdentifierName(string $identifier) : string { // Always generate name for unquoted identifiers to ensure consistency. $identifier = new Identifier($identifier); diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index b7382ec08b0..7cf1b7b3fbf 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -1,5 +1,7 @@ multiplyInterval($interval, 7); + $unit = DateIntervalUnit::DAY; + break; - return 'DATE(' . $date . ",'" . $operator . $interval . ' ' . $unit . "')"; + case DateIntervalUnit::QUARTER: + $interval = $this->multiplyInterval($interval, 3); + $unit = DateIntervalUnit::MONTH; + break; } + + return 'DATETIME(' . $date . ',' . $this->getConcatExpression( + $this->quoteStringLiteral($operator), + $interval, + $this->quoteStringLiteral(' ' . $unit) + ) . ')'; } /** * {@inheritDoc} */ - public function getDateDiffExpression($date1, $date2) + public function getDateDiffExpression(string $date1, string $date2) : string { return sprintf("JULIANDAY(%s, 'start of day') - JULIANDAY(%s, 'start of day')", $date1, $date2); } @@ -161,15 +153,15 @@ public function getDateDiffExpression($date1, $date2) /** * {@inheritDoc} */ - protected function _getTransactionIsolationLevelSQL($level) + protected function _getTransactionIsolationLevelSQL(int $level) : string { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: - return 0; + return '0'; case TransactionIsolationLevel::READ_COMMITTED: case TransactionIsolationLevel::REPEATABLE_READ: case TransactionIsolationLevel::SERIALIZABLE: - return 1; + return '1'; default: return parent::_getTransactionIsolationLevelSQL($level); } @@ -178,7 +170,7 @@ protected function _getTransactionIsolationLevelSQL($level) /** * {@inheritDoc} */ - public function getSetTransactionIsolationSQL($level) + public function getSetTransactionIsolationSQL(int $level) : string { return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level); } @@ -186,7 +178,7 @@ public function getSetTransactionIsolationSQL($level) /** * {@inheritDoc} */ - public function prefersIdentityColumns() + public function prefersIdentityColumns() : bool { return true; } @@ -194,7 +186,7 @@ public function prefersIdentityColumns() /** * {@inheritDoc} */ - public function getBooleanTypeDeclarationSQL(array $field) + public function getBooleanTypeDeclarationSQL(array $columnDef) : string { return 'BOOLEAN'; } @@ -202,28 +194,28 @@ public function getBooleanTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getIntegerTypeDeclarationSQL(array $field) + public function getIntegerTypeDeclarationSQL(array $columnDef) : string { - return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getBigIntTypeDeclarationSQL(array $field) + public function getBigIntTypeDeclarationSQL(array $columnDef) : string { // SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT fields. - if (! empty($field['autoincrement'])) { - return $this->getIntegerTypeDeclarationSQL($field); + if (! empty($columnDef['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($columnDef); } - return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getTinyIntTypeDeclarationSql(array $field) + public function getTinyIntTypeDeclarationSql(array $field) : string { // SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT fields. if (! empty($field['autoincrement'])) { @@ -236,20 +228,20 @@ public function getTinyIntTypeDeclarationSql(array $field) /** * {@inheritDoc} */ - public function getSmallIntTypeDeclarationSQL(array $field) + public function getSmallIntTypeDeclarationSQL(array $columnDef) : string { // SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT fields. - if (! empty($field['autoincrement'])) { - return $this->getIntegerTypeDeclarationSQL($field); + if (! empty($columnDef['autoincrement'])) { + return $this->getIntegerTypeDeclarationSQL($columnDef); } - return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ - public function getMediumIntTypeDeclarationSql(array $field) + public function getMediumIntTypeDeclarationSql(array $field) : string { // SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT fields. if (! empty($field['autoincrement'])) { @@ -262,7 +254,7 @@ public function getMediumIntTypeDeclarationSql(array $field) /** * {@inheritDoc} */ - public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATETIME'; } @@ -270,7 +262,7 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getDateTypeDeclarationSQL(array $fieldDeclaration) + public function getDateTypeDeclarationSQL(array $fieldDeclaration) : string { return 'DATE'; } @@ -278,7 +270,7 @@ public function getDateTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) : string { return 'TIME'; } @@ -286,7 +278,7 @@ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) /** * {@inheritDoc} */ - protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) : string { // sqlite autoincrement is only possible for the primary key if (! empty($columnDef['autoincrement'])) { @@ -299,7 +291,7 @@ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) /** * {@inheritDoc} */ - public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) + public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) : string { return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint( $foreignKey->getQuotedLocalColumns($this), @@ -313,9 +305,9 @@ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) /** * {@inheritDoc} */ - protected function _getCreateTableSQL($name, array $columns, array $options = []) + protected function _getCreateTableSQL(string $tableName, array $columns, array $options = []) : array { - $name = str_replace('.', '__', $name); + $tableName = str_replace('.', '__', $tableName); $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { @@ -332,7 +324,7 @@ protected function _getCreateTableSQL($name, array $columns, array $options = [] } } - $query = ['CREATE TABLE ' . $name . ' (' . $queryFields . ')']; + $query = ['CREATE TABLE ' . $tableName . ' (' . $queryFields . ')']; if (isset($options['alter']) && $options['alter'] === true) { return $query; @@ -340,13 +332,13 @@ protected function _getCreateTableSQL($name, array $columns, array $options = [] if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $indexDef) { - $query[] = $this->getCreateIndexSQL($indexDef, $name); + $query[] = $this->getCreateIndexSQL($indexDef, $tableName); } } if (isset($options['unique']) && ! empty($options['unique'])) { foreach ($options['unique'] as $indexDef) { - $query[] = $this->getCreateIndexSQL($indexDef, $name); + $query[] = $this->getCreateIndexSQL($indexDef, $tableName); } } @@ -368,27 +360,20 @@ private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $ $keyColumns = array_unique(array_values($options['primary'])); foreach ($keyColumns as $keyColumn) { - if (! empty($columns[$keyColumn]['autoincrement'])) { - return ''; + foreach ($columns as $column) { + if ($column['name'] === $keyColumn && ! empty($column['autoincrement'])) { + return ''; + } } } return ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } - /** - * {@inheritDoc} - */ - protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) - { - return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') - : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); - } - /** * {@inheritdoc} */ - protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) + protected function getBinaryTypeDeclarationSQLSnippet(?int $length) : string { return 'BLOB'; } @@ -396,23 +381,29 @@ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) /** * {@inheritdoc} */ - public function getBinaryMaxLength() + protected function getVarcharTypeDeclarationSQLSnippet(?int $length) : string { - return 0; + $sql = 'VARCHAR'; + + if ($length !== null) { + $sql .= sprintf('(%d)', $length); + } + + return $sql; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getBinaryDefaultLength() + protected function getVarbinaryTypeDeclarationSQLSnippet(?int $length) : string { - return 0; + return 'BLOB'; } /** * {@inheritDoc} */ - public function getClobTypeDeclarationSQL(array $field) + public function getClobTypeDeclarationSQL(array $field) : string { return 'CLOB'; } @@ -420,7 +411,7 @@ public function getClobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getListTableConstraintsSQL($table) + public function getListTableConstraintsSQL(string $table) : string { $table = str_replace('.', '__', $table); @@ -433,7 +424,7 @@ public function getListTableConstraintsSQL($table) /** * {@inheritDoc} */ - public function getListTableColumnsSQL($table, $currentDatabase = null) + public function getListTableColumnsSQL(string $table, ?string $database = null) : string { $table = str_replace('.', '__', $table); @@ -443,7 +434,7 @@ public function getListTableColumnsSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getListTableIndexesSQL($table, $currentDatabase = null) + public function getListTableIndexesSQL(string $table, ?string $currentDatabase = null) : string { $table = str_replace('.', '__', $table); @@ -453,7 +444,7 @@ public function getListTableIndexesSQL($table, $currentDatabase = null) /** * {@inheritDoc} */ - public function getListTablesSQL() + public function getListTablesSQL() : string { return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' " . 'UNION ALL SELECT name FROM sqlite_temp_master ' @@ -463,7 +454,7 @@ public function getListTablesSQL() /** * {@inheritDoc} */ - public function getListViewsSQL($database) + public function getListViewsSQL(string $database) : string { return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; } @@ -471,7 +462,7 @@ public function getListViewsSQL($database) /** * {@inheritDoc} */ - public function getCreateViewSQL($name, $sql) + public function getCreateViewSQL(string $name, string $sql) : string { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } @@ -479,7 +470,7 @@ public function getCreateViewSQL($name, $sql) /** * {@inheritDoc} */ - public function getDropViewSQL($name) + public function getDropViewSQL(string $name) : string { return 'DROP VIEW ' . $name; } @@ -487,7 +478,7 @@ public function getDropViewSQL($name) /** * {@inheritDoc} */ - public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) : string { $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey); @@ -500,7 +491,7 @@ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey /** * {@inheritDoc} */ - public function supportsIdentityColumns() + public function supportsIdentityColumns() : bool { return true; } @@ -508,7 +499,7 @@ public function supportsIdentityColumns() /** * {@inheritDoc} */ - public function supportsColumnCollation() + public function supportsColumnCollation() : bool { return true; } @@ -516,7 +507,7 @@ public function supportsColumnCollation() /** * {@inheritDoc} */ - public function supportsInlineColumnComments() + public function supportsInlineColumnComments() : bool { return true; } @@ -524,7 +515,7 @@ public function supportsInlineColumnComments() /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'sqlite'; } @@ -532,7 +523,7 @@ public function getName() /** * {@inheritDoc} */ - public function getTruncateTableSQL($tableName, $cascade = false) + public function getTruncateTableSQL(string $tableName, bool $cascade = false) : string { $tableIdentifier = new Identifier($tableName); $tableName = str_replace('.', '__', $tableIdentifier->getQuotedName($this)); @@ -544,35 +535,21 @@ public function getTruncateTableSQL($tableName, $cascade = false) * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction(). * * @param int|float $value - * - * @return float */ - public static function udfSqrt($value) + public static function udfSqrt($value) : float { return sqrt($value); } /** * User-defined function for Sqlite that implements MOD(a, b). - * - * @param int $a - * @param int $b - * - * @return int */ - public static function udfMod($a, $b) + public static function udfMod(int $a, int $b) : int { return $a % $b; } - /** - * @param string $str - * @param string $substr - * @param int $offset - * - * @return int - */ - public static function udfLocate($str, $substr, $offset = 0) + public static function udfLocate(string $str, string $substr, int $offset = 0) : int { // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions. // So we have to make them compatible if an offset is given. @@ -592,7 +569,7 @@ public static function udfLocate($str, $substr, $offset = 0) /** * {@inheritDoc} */ - public function getForUpdateSql() + public function getForUpdateSql() : string { return ''; } @@ -600,56 +577,61 @@ public function getForUpdateSql() /** * {@inheritDoc} */ - public function getInlineColumnCommentSQL($comment) + public function getInlineColumnCommentSQL(?string $comment) : string { + if ($comment === null || $comment === '') { + return ''; + } + return '--' . str_replace("\n", "\n--", $comment) . "\n"; } /** * {@inheritDoc} */ - protected function initializeDoctrineTypeMappings() + protected function initializeDoctrineTypeMappings() : void { $this->doctrineTypeMapping = [ - 'boolean' => 'boolean', - 'tinyint' => 'boolean', - 'smallint' => 'smallint', - 'mediumint' => 'integer', - 'int' => 'integer', - 'integer' => 'integer', - 'serial' => 'integer', 'bigint' => 'bigint', 'bigserial' => 'bigint', - 'clob' => 'text', - 'tinytext' => 'text', - 'mediumtext' => 'text', - 'longtext' => 'text', - 'text' => 'text', - 'varchar' => 'string', - 'longvarchar' => 'string', - 'varchar2' => 'string', - 'nvarchar' => 'string', - 'image' => 'string', - 'ntext' => 'string', + 'blob' => 'blob', + 'boolean' => 'boolean', 'char' => 'string', + 'clob' => 'text', 'date' => 'date', 'datetime' => 'datetime', - 'timestamp' => 'datetime', - 'time' => 'time', - 'float' => 'float', + 'decimal' => 'decimal', 'double' => 'float', 'double precision' => 'float', - 'real' => 'float', - 'decimal' => 'decimal', + 'float' => 'float', + 'image' => 'string', + 'int' => 'integer', + 'integer' => 'integer', + 'longtext' => 'text', + 'longvarchar' => 'string', + 'mediumint' => 'integer', + 'mediumtext' => 'text', + 'ntext' => 'string', 'numeric' => 'decimal', - 'blob' => 'blob', + 'nvarchar' => 'string', + 'real' => 'float', + 'serial' => 'integer', + 'smallint' => 'smallint', + 'string' => 'string', + 'text' => 'text', + 'time' => 'time', + 'timestamp' => 'datetime', + 'tinyint' => 'boolean', + 'tinytext' => 'text', + 'varchar' => 'string', + 'varchar2' => 'string', ]; } /** * {@inheritDoc} */ - protected function getReservedKeywordsClass() + protected function getReservedKeywordsClass() : string { return Keywords\SQLiteKeywords::class; } @@ -657,10 +639,10 @@ protected function getReservedKeywordsClass() /** * {@inheritDoc} */ - protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) : array { if (! $diff->fromTable instanceof Table) { - throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); + throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema.'); } $sql = []; @@ -678,16 +660,16 @@ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) /** * {@inheritDoc} */ - protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) : array { if (! $diff->fromTable instanceof Table) { - throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); + throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema.'); } $sql = []; $tableName = $diff->getNewName(); - if ($tableName === false) { + if ($tableName === null) { $tableName = $diff->getName($this); } @@ -705,10 +687,10 @@ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) /** * {@inheritDoc} */ - protected function doModifyLimitQuery($query, $limit, $offset) + protected function doModifyLimitQuery(string $query, ?int $limit, int $offset) : string { if ($limit === null && $offset > 0) { - return $query . ' LIMIT -1 OFFSET ' . $offset; + $limit = -1; } return parent::doModifyLimitQuery($query, $limit, $offset); @@ -717,7 +699,7 @@ protected function doModifyLimitQuery($query, $limit, $offset) /** * {@inheritDoc} */ - public function getBlobTypeDeclarationSQL(array $field) + public function getBlobTypeDeclarationSQL(array $field) : string { return 'BLOB'; } @@ -725,7 +707,7 @@ public function getBlobTypeDeclarationSQL(array $field) /** * {@inheritDoc} */ - public function getTemporaryTableName($tableName) + public function getTemporaryTableName(string $tableName) : string { $tableName = str_replace('.', '__', $tableName); @@ -741,7 +723,7 @@ public function getTemporaryTableName($tableName) * This hack is implemented to be able to use SQLite as testdriver when * using schema supporting databases. */ - public function canEmulateSchemas() + public function canEmulateSchemas() : bool { return true; } @@ -749,7 +731,7 @@ public function canEmulateSchemas() /** * {@inheritDoc} */ - public function supportsForeignKeyConstraints() + public function supportsForeignKeyConstraints() : bool { return false; } @@ -757,7 +739,7 @@ public function supportsForeignKeyConstraints() /** * {@inheritDoc} */ - public function getCreatePrimaryKeySQL(Index $index, $table) + public function getCreatePrimaryKeySQL(Index $index, $table) : string { throw new DBALException('Sqlite platform does not support alter primary key.'); } @@ -765,7 +747,7 @@ public function getCreatePrimaryKeySQL(Index $index, $table) /** * {@inheritdoc} */ - public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) : string { throw new DBALException('Sqlite platform does not support alter foreign key.'); } @@ -773,7 +755,7 @@ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) /** * {@inheritdoc} */ - public function getDropForeignKeySQL($foreignKey, $table) + public function getDropForeignKeySQL($foreignKey, $table) : string { throw new DBALException('Sqlite platform does not support alter foreign key.'); } @@ -781,7 +763,7 @@ public function getDropForeignKeySQL($foreignKey, $table) /** * {@inheritDoc} */ - public function getCreateConstraintSQL(Constraint $constraint, $table) + public function getCreateConstraintSQL(Constraint $constraint, $table) : string { throw new DBALException('Sqlite platform does not support alter constraint.'); } @@ -789,17 +771,15 @@ public function getCreateConstraintSQL(Constraint $constraint, $table) /** * {@inheritDoc} */ - public function getCreateTableSQL(Table $table, $createFlags = null) + public function getCreateTableSQL(Table $table, int $createFlags = self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS) : array { - $createFlags = $createFlags ?? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS; - return parent::getCreateTableSQL($table, $createFlags); } /** * {@inheritDoc} */ - public function getListTableForeignKeysSQL($table, $database = null) + public function getListTableForeignKeysSQL(string $table, ?string $database = null) : string { $table = str_replace('.', '__', $table); @@ -809,7 +789,7 @@ public function getListTableForeignKeysSQL($table, $database = null) /** * {@inheritDoc} */ - public function getAlterTableSQL(TableDiff $diff) + public function getAlterTableSQL(TableDiff $diff) : array { $sql = $this->getSimpleAlterTableSQL($diff); if ($sql !== false) { @@ -818,7 +798,7 @@ public function getAlterTableSQL(TableDiff $diff) $fromTable = $diff->fromTable; if (! $fromTable instanceof Table) { - throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); + throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema.'); } $table = clone $fromTable; @@ -898,10 +878,11 @@ public function getAlterTableSQL(TableDiff $diff) $sql = []; $tableSql = []; + if (! $this->onSchemaAlterTable($diff, $tableSql)) { $dataTable = new Table('__temp__' . $table->getName()); - $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions()); + $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), [], $this->getForeignKeysInAlteredTable($diff), $table->getOptions()); $newTable->addOption('alter', true); $sql = $this->getPreAlterTableIndexForeignKeySQL($diff); @@ -915,7 +896,7 @@ public function getAlterTableSQL(TableDiff $diff) $newName = $diff->getNewName(); - if ($newName !== false) { + if ($newName !== null) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $newTable->getQuotedName($this), @@ -997,7 +978,7 @@ private function getSimpleAlterTableSQL(TableDiff $diff) } if (! $this->onSchemaAlterTable($diff, $tableSql)) { - if ($diff->newName !== false) { + if ($diff->newName !== null) { $newTable = new Identifier($diff->newName); $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' RENAME TO ' . $newTable->getQuotedName($this); } @@ -1009,7 +990,7 @@ private function getSimpleAlterTableSQL(TableDiff $diff) /** * @return string[] */ - private function getColumnNamesInAlteredTable(TableDiff $diff) + private function getColumnNamesInAlteredTable(TableDiff $diff) : array { $columns = []; @@ -1049,7 +1030,7 @@ private function getColumnNamesInAlteredTable(TableDiff $diff) /** * @return Index[] */ - private function getIndexesInAlteredTable(TableDiff $diff) + private function getIndexesInAlteredTable(TableDiff $diff) : array { $indexes = $diff->fromTable->getIndexes(); $columnNames = $this->getColumnNamesInAlteredTable($diff); @@ -1088,18 +1069,20 @@ private function getIndexesInAlteredTable(TableDiff $diff) } foreach ($diff->removedIndexes as $index) { - $indexName = strtolower($index->getName()); - if (! strlen($indexName) || ! isset($indexes[$indexName])) { + $indexName = $index->getName(); + + if ($indexName === '') { continue; } - unset($indexes[$indexName]); + unset($indexes[strtolower($indexName)]); } foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) { - $indexName = strtolower($index->getName()); - if (strlen($indexName)) { - $indexes[$indexName] = $index; + $indexName = $index->getName(); + + if ($indexName !== '') { + $indexes[strtolower($indexName)] = $index; } else { $indexes[] = $index; } @@ -1111,7 +1094,7 @@ private function getIndexesInAlteredTable(TableDiff $diff) /** * @return ForeignKeyConstraint[] */ - private function getForeignKeysInAlteredTable(TableDiff $diff) + private function getForeignKeysInAlteredTable(TableDiff $diff) : array { $foreignKeys = $diff->fromTable->getForeignKeys(); $columnNames = $this->getColumnNamesInAlteredTable($diff); @@ -1146,18 +1129,20 @@ private function getForeignKeysInAlteredTable(TableDiff $diff) $constraint = new Identifier($constraint); } - $constraintName = strtolower($constraint->getName()); - if (! strlen($constraintName) || ! isset($foreignKeys[$constraintName])) { + $constraintName = $constraint->getName(); + + if ($constraintName === '') { continue; } - unset($foreignKeys[$constraintName]); + unset($foreignKeys[strtolower($constraintName)]); } foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) { - $constraintName = strtolower($constraint->getName()); - if (strlen($constraintName)) { - $foreignKeys[$constraintName] = $constraint; + $constraintName = $constraint->getName(); + + if ($constraintName !== '') { + $foreignKeys[strtolower($constraintName)] = $constraint; } else { $foreignKeys[] = $constraint; } @@ -1169,7 +1154,7 @@ private function getForeignKeysInAlteredTable(TableDiff $diff) /** * @return Index[] */ - private function getPrimaryIndexInAlteredTable(TableDiff $diff) + private function getPrimaryIndexInAlteredTable(TableDiff $diff) : array { $primaryIndex = []; diff --git a/lib/Doctrine/DBAL/Portability/Connection.php b/lib/Doctrine/DBAL/Portability/Connection.php index 7b4af8a8799..db687b167b4 100644 --- a/lib/Doctrine/DBAL/Portability/Connection.php +++ b/lib/Doctrine/DBAL/Portability/Connection.php @@ -1,14 +1,17 @@ getParams(); - if (isset($params['portability'])) { - if ($this->getDatabasePlatform()->getName() === 'oracle') { - $params['portability'] &= self::PORTABILITY_ORACLE; - } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { - $params['portability'] &= self::PORTABILITY_POSTGRESQL; - } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { - $params['portability'] &= self::PORTABILITY_SQLITE; - } elseif ($this->getDatabasePlatform()->getName() === 'drizzle') { - $params['portability'] &= self::PORTABILITY_DRIZZLE; - } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { - $params['portability'] &= self::PORTABILITY_SQLANYWHERE; - } elseif ($this->getDatabasePlatform()->getName() === 'db2') { - $params['portability'] &= self::PORTABILITY_DB2; - } elseif ($this->getDatabasePlatform()->getName() === 'mssql') { - $params['portability'] &= self::PORTABILITY_SQLSRV; - } else { - $params['portability'] &= self::PORTABILITY_OTHERVENDORS; - } - $this->portability = $params['portability']; - } + if ($this->isConnected()) { + return; + } - if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { - if ($this->_conn instanceof PDOConnection) { - // make use of c-level support for case handling - $this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); - } else { - $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; - } + parent::connect(); + + $params = $this->getParams(); + + if (isset($params['portability'])) { + if ($this->getDatabasePlatform()->getName() === 'oracle') { + $params['portability'] &= self::PORTABILITY_ORACLE; + } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { + $params['portability'] &= self::PORTABILITY_POSTGRESQL; + } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { + $params['portability'] &= self::PORTABILITY_SQLITE; + } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { + $params['portability'] &= self::PORTABILITY_SQLANYWHERE; + } elseif ($this->getDatabasePlatform()->getName() === 'db2') { + $params['portability'] &= self::PORTABILITY_DB2; + } elseif ($this->getDatabasePlatform()->getName() === 'mssql') { + $params['portability'] &= self::PORTABILITY_SQLSRV; + } else { + $params['portability'] &= self::PORTABILITY_OTHERVENDORS; } + $this->portability = $params['portability']; + } + + if (! isset($params['fetch_case']) || ! ($this->portability & self::PORTABILITY_FIX_CASE)) { + return; } - return $ret; + if ($this->_conn instanceof PDOConnection) { + // make use of c-level support for case handling + $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); + } else { + $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; + } } - /** - * @return int - */ - public function getPortability() + public function getPortability() : int { return $this->portability; } - /** - * @return int - */ - public function getFetchCase() + public function getFetchCase() : ?int { return $this->case; } @@ -97,7 +95,7 @@ public function getFetchCase() /** * {@inheritdoc} */ - public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) + public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement { $stmt = new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); $stmt->setFetchMode($this->defaultFetchMode); @@ -108,9 +106,9 @@ public function executeQuery($query, array $params = [], $types = [], ?QueryCach /** * {@inheritdoc} */ - public function prepare($statement) + public function prepare(string $sql) : DriverStatement { - $stmt = new Statement(parent::prepare($statement), $this); + $stmt = new Statement(parent::prepare($sql), $this); $stmt->setFetchMode($this->defaultFetchMode); return $stmt; @@ -119,11 +117,11 @@ public function prepare($statement) /** * {@inheritdoc} */ - public function query() + public function query(string $sql) : ResultStatement { $connection = $this->getWrappedConnection(); - $stmt = $connection->query(...func_get_args()); + $stmt = $connection->query($sql); $stmt = new Statement($stmt, $this); $stmt->setFetchMode($this->defaultFetchMode); diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index 514b3be2d74..9df3169ed84 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -1,5 +1,7 @@ stmt instanceof DriverStatement); - return $this->stmt->bindParam($column, $variable, $type, $length); + $this->stmt->bindParam($param, $variable, $type, $length); } /** * {@inheritdoc} */ - public function bindValue($param, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, int $type = ParameterType::STRING) : void { assert($this->stmt instanceof DriverStatement); - return $this->stmt->bindValue($param, $value, $type); + $this->stmt->bindValue($param, $value, $type); } /** * {@inheritdoc} */ - public function closeCursor() + public function closeCursor() : void { - return $this->stmt->closeCursor(); + $this->stmt->closeCursor(); } /** * {@inheritdoc} */ - public function columnCount() + public function columnCount() : int { return $this->stmt->columnCount(); } @@ -82,41 +83,21 @@ public function columnCount() /** * {@inheritdoc} */ - public function errorCode() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() + public function execute(?array $params = null) : void { assert($this->stmt instanceof DriverStatement); - return $this->stmt->errorInfo(); + $this->stmt->execute($params); } /** * {@inheritdoc} */ - public function execute($params = null) - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->execute($params); - } - - /** - * {@inheritdoc} - */ - public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { $this->defaultFetchMode = $fetchMode; - return $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); + $this->stmt->setFetchMode($fetchMode, ...$args); } /** @@ -130,13 +111,13 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { $fetchMode = $fetchMode ?: $this->defaultFetchMode; - $row = $this->stmt->fetch($fetchMode); + $row = $this->stmt->fetch($fetchMode, ...$args); - $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); + $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0; $fixCase = $this->case !== null && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) && ($this->portability & Connection::PORTABILITY_FIX_CASE); @@ -149,17 +130,13 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { $fetchMode = $fetchMode ?: $this->defaultFetchMode; - if ($fetchArgument) { - $rows = $this->stmt->fetchAll($fetchMode, $fetchArgument); - } else { - $rows = $this->stmt->fetchAll($fetchMode); - } + $rows = $this->stmt->fetchAll($fetchMode, ...$args); - $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); + $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0; $fixCase = $this->case !== null && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) && ($this->portability & Connection::PORTABILITY_FIX_CASE); @@ -189,12 +166,10 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * @param mixed $row - * @param int $iterateRow - * @param bool $fixCase * * @return mixed */ - protected function fixRow($row, $iterateRow, $fixCase) + protected function fixRow($row, bool $iterateRow, bool $fixCase) { if (! $row) { return $row; @@ -220,7 +195,7 @@ protected function fixRow($row, $iterateRow, $fixCase) /** * {@inheritdoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { $value = $this->stmt->fetchColumn($columnIndex); @@ -238,7 +213,7 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} */ - public function rowCount() + public function rowCount() : int { assert($this->stmt instanceof DriverStatement); diff --git a/lib/Doctrine/DBAL/Query/Exception/NonUniqueAlias.php b/lib/Doctrine/DBAL/Query/Exception/NonUniqueAlias.php new file mode 100644 index 00000000000..fdd20a9a8ce --- /dev/null +++ b/lib/Doctrine/DBAL/Query/Exception/NonUniqueAlias.php @@ -0,0 +1,27 @@ +type = $type; @@ -49,11 +51,11 @@ public function __construct($type, array $parts = []) /** * Adds multiple parts to composite expression. * - * @param self[]|string[] $parts + * @param array $parts * - * @return \Doctrine\DBAL\Query\Expression\CompositeExpression + * @return $this */ - public function addMultiple(array $parts = []) + public function addMultiple(array $parts = []) : self { foreach ($parts as $part) { $this->add($part); @@ -65,11 +67,11 @@ public function addMultiple(array $parts = []) /** * Adds an expression to composite expression. * - * @param mixed $part + * @param self|string $part * - * @return \Doctrine\DBAL\Query\Expression\CompositeExpression + * @return $this */ - public function add($part) + public function add($part) : self { if (empty($part)) { return $this; @@ -86,20 +88,16 @@ public function add($part) /** * Retrieves the amount of expressions on composite expression. - * - * @return int */ - public function count() + public function count() : int { return count($this->parts); } /** * Retrieves the string representation of this composite expression. - * - * @return string */ - public function __toString() + public function __toString() : string { if ($this->count() === 1) { return (string) $this->parts[0]; @@ -110,10 +108,8 @@ public function __toString() /** * Returns the type of this composite expression (AND/OR). - * - * @return string */ - public function getType() + public function getType() : string { return $this->type; } diff --git a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php index dfcc31ec709..8aac8662797 100644 --- a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php +++ b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php @@ -1,5 +1,7 @@ comparison($x, self::EQ, $y); } @@ -121,10 +115,8 @@ public function eq($x, $y) * * @param mixed $x The left expression. * @param mixed $y The right expression. - * - * @return string */ - public function neq($x, $y) + public function neq($x, $y) : string { return $this->comparison($x, self::NEQ, $y); } @@ -140,10 +132,8 @@ public function neq($x, $y) * * @param mixed $x The left expression. * @param mixed $y The right expression. - * - * @return string */ - public function lt($x, $y) + public function lt($x, $y) : string { return $this->comparison($x, self::LT, $y); } @@ -159,10 +149,8 @@ public function lt($x, $y) * * @param mixed $x The left expression. * @param mixed $y The right expression. - * - * @return string */ - public function lte($x, $y) + public function lte($x, $y) : string { return $this->comparison($x, self::LTE, $y); } @@ -178,10 +166,8 @@ public function lte($x, $y) * * @param mixed $x The left expression. * @param mixed $y The right expression. - * - * @return string */ - public function gt($x, $y) + public function gt($x, $y) : string { return $this->comparison($x, self::GT, $y); } @@ -197,10 +183,8 @@ public function gt($x, $y) * * @param mixed $x The left expression. * @param mixed $y The right expression. - * - * @return string */ - public function gte($x, $y) + public function gte($x, $y) : string { return $this->comparison($x, self::GTE, $y); } @@ -209,10 +193,8 @@ public function gte($x, $y) * Creates an IS NULL expression with the given arguments. * * @param string $x The field in string format to be restricted by IS NULL. - * - * @return string */ - public function isNull($x) + public function isNull(string $x) : string { return $x . ' IS NULL'; } @@ -221,10 +203,8 @@ public function isNull($x) * Creates an IS NOT NULL expression with the given arguments. * * @param string $x The field in string format to be restricted by IS NOT NULL. - * - * @return string */ - public function isNotNull($x) + public function isNotNull(string $x) : string { return $x . ' IS NOT NULL'; } @@ -234,10 +214,8 @@ public function isNotNull($x) * * @param string $x Field in string format to be inspected by LIKE() comparison. * @param mixed $y Argument to be used in LIKE() comparison. - * - * @return string */ - public function like($x, $y/*, ?string $escapeChar = null */) + public function like(string $x, $y/*, ?string $escapeChar = null */) : string { return $this->comparison($x, 'LIKE', $y) . (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); @@ -248,10 +226,8 @@ public function like($x, $y/*, ?string $escapeChar = null */) * * @param string $x Field in string format to be inspected by NOT LIKE() comparison. * @param mixed $y Argument to be used in NOT LIKE() comparison. - * - * @return string */ - public function notLike($x, $y/*, ?string $escapeChar = null */) + public function notLike(string $x, $y/*, ?string $escapeChar = null */) : string { return $this->comparison($x, 'NOT LIKE', $y) . (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); @@ -262,10 +238,8 @@ public function notLike($x, $y/*, ?string $escapeChar = null */) * * @param string $x The field in string format to be inspected by IN() comparison. * @param string|string[] $y The placeholder or the array of values to be used by IN() comparison. - * - * @return string */ - public function in($x, $y) + public function in(string $x, $y) : string { return $this->comparison($x, 'IN', '(' . implode(', ', (array) $y) . ')'); } @@ -275,24 +249,17 @@ public function in($x, $y) * * @param string $x The field in string format to be inspected by NOT IN() comparison. * @param string|string[] $y The placeholder or the array of values to be used by NOT IN() comparison. - * - * @return string */ - public function notIn($x, $y) + public function notIn(string $x, $y) : string { return $this->comparison($x, 'NOT IN', '(' . implode(', ', (array) $y) . ')'); } /** - * Quotes a given input parameter. - * - * @param mixed $input The parameter to be quoted. - * @param int|null $type The type of the parameter. - * - * @return string + * Creates an SQL literal expression from the string. */ - public function literal($input, $type = null) + public function literal(string $input) : string { - return $this->connection->quote($input, $type); + return $this->connection->quote($input); } } diff --git a/lib/Doctrine/DBAL/Query/QueryBuilder.php b/lib/Doctrine/DBAL/Query/QueryBuilder.php index 50c08655ff3..d1e6d31dab5 100644 --- a/lib/Doctrine/DBAL/Query/QueryBuilder.php +++ b/lib/Doctrine/DBAL/Query/QueryBuilder.php @@ -1,10 +1,14 @@ */ private $sqlParts = [ 'select' => [], @@ -79,14 +83,14 @@ class QueryBuilder /** * The query parameters. * - * @var mixed[] + * @var array|array */ private $params = []; /** * The parameter type map of this query. * - * @var int[]|string[] + * @var array|array */ private $paramTypes = []; @@ -109,14 +113,14 @@ class QueryBuilder * * @var int */ - private $firstResult = null; + private $firstResult = 0; /** * The maximum number of results to retrieve. * - * @var int + * @var int|null */ - private $maxResults = null; + private $maxResults; /** * The counter of bound parameters used with {@see bindValue). @@ -148,30 +152,24 @@ public function __construct(Connection $connection) * * For more complex expression construction, consider storing the expression * builder object in a local variable. - * - * @return ExpressionBuilder */ - public function expr() + public function expr() : ExpressionBuilder { return $this->connection->getExpressionBuilder(); } /** * Gets the type of the currently built query. - * - * @return int */ - public function getType() + public function getType() : int { return $this->type; } /** * Gets the associated DBAL Connection for this query builder. - * - * @return Connection */ - public function getConnection() + public function getConnection() : Connection { return $this->connection; } @@ -181,7 +179,7 @@ public function getConnection() * * @return int Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. */ - public function getState() + public function getState() : int { return $this->state; } @@ -215,7 +213,7 @@ public function execute() * * @return string The SQL query string. */ - public function getSQL() + public function getSQL() : string { if ($this->sql !== null && $this->state === self::STATE_CLEAN) { return $this->sql; @@ -262,7 +260,7 @@ public function getSQL() * * @return $this This QueryBuilder instance. */ - public function setParameter($key, $value, $type = null) + public function setParameter($key, $value, $type = null) : self { if ($type !== null) { $this->paramTypes[$key] = $type; @@ -287,12 +285,12 @@ public function setParameter($key, $value, $type = null) * )); * * - * @param mixed[] $params The query parameters to set. - * @param int[]|string[] $types The query parameters types to set. + * @param array|array $params The query parameters to set. + * @param array|array $types The query parameters types to set. * * @return $this This QueryBuilder instance. */ - public function setParameters(array $params, array $types = []) + public function setParameters(array $params, array $types = []) : self { $this->paramTypes = $types; $this->params = $params; @@ -303,9 +301,9 @@ public function setParameters(array $params, array $types = []) /** * Gets all defined query parameters for the query being constructed indexed by parameter index or name. * - * @return mixed[] The currently defined query parameters indexed by parameter index or name. + * @return array The currently defined query parameters indexed by parameter index or name. */ - public function getParameters() + public function getParameters() : array { return $this->params; } @@ -313,7 +311,7 @@ public function getParameters() /** * Gets a (previously set) query parameter of the query being constructed. * - * @param mixed $key The key (index or name) of the bound parameter. + * @param string|int $key The key (index or name) of the bound parameter. * * @return mixed The value of the bound parameter. */ @@ -325,9 +323,9 @@ public function getParameter($key) /** * Gets all defined query parameter types for the query being constructed indexed by parameter index or name. * - * @return int[]|string[] The currently defined query parameter types indexed by parameter index or name. + * @return array The currently defined query parameter types indexed by parameter index or name. */ - public function getParameterTypes() + public function getParameterTypes() : array { return $this->paramTypes; } @@ -335,7 +333,7 @@ public function getParameterTypes() /** * Gets a (previously set) query parameter type of the query being constructed. * - * @param mixed $key The key (index or name) of the bound parameter type. + * @param string|int $key The key (index or name) of the bound parameter type. * * @return mixed The value of the bound parameter type. */ @@ -351,7 +349,7 @@ public function getParameterType($key) * * @return $this This QueryBuilder instance. */ - public function setFirstResult($firstResult) + public function setFirstResult(int $firstResult) : self { $this->state = self::STATE_DIRTY; $this->firstResult = $firstResult; @@ -365,7 +363,7 @@ public function setFirstResult($firstResult) * * @return int The position of the first result. */ - public function getFirstResult() + public function getFirstResult() : int { return $this->firstResult; } @@ -377,7 +375,7 @@ public function getFirstResult() * * @return $this This QueryBuilder instance. */ - public function setMaxResults($maxResults) + public function setMaxResults(int $maxResults) : self { $this->state = self::STATE_DIRTY; $this->maxResults = $maxResults; @@ -391,7 +389,7 @@ public function setMaxResults($maxResults) * * @return int The maximum number of results. */ - public function getMaxResults() + public function getMaxResults() : int { return $this->maxResults; } @@ -402,13 +400,11 @@ public function getMaxResults() * The available parts are: 'select', 'from', 'set', 'where', * 'groupBy', 'having' and 'orderBy'. * - * @param string $sqlPartName - * @param mixed $sqlPart - * @param bool $append + * @param mixed $sqlPart * * @return $this This QueryBuilder instance. */ - public function add($sqlPartName, $sqlPart, $append = false) + public function add(string $sqlPartName, $sqlPart, bool $append = false) : self { $isArray = is_array($sqlPart); $isMultiple = is_array($this->sqlParts[$sqlPartName]); @@ -456,7 +452,7 @@ public function add($sqlPartName, $sqlPart, $append = false) * * @return $this This QueryBuilder instance. */ - public function select($select = null) + public function select($select = null) : self { $this->type = self::SELECT; @@ -484,7 +480,7 @@ public function select($select = null) * * @return $this This QueryBuilder instance. */ - public function addSelect($select = null) + public function addSelect($select = null) : self { $this->type = self::SELECT; @@ -513,7 +509,7 @@ public function addSelect($select = null) * * @return $this This QueryBuilder instance. */ - public function delete($delete = null, $alias = null) + public function delete(?string $delete = null, ?string $alias = null) : self { $this->type = self::DELETE; @@ -543,7 +539,7 @@ public function delete($delete = null, $alias = null) * * @return $this This QueryBuilder instance. */ - public function update($update = null, $alias = null) + public function update(?string $update = null, ?string $alias = null) : self { $this->type = self::UPDATE; @@ -576,7 +572,7 @@ public function update($update = null, $alias = null) * * @return $this This QueryBuilder instance. */ - public function insert($insert = null) + public function insert(?string $insert = null) : self { $this->type = self::INSERT; @@ -602,7 +598,7 @@ public function insert($insert = null) * * @return $this This QueryBuilder instance. */ - public function from($from, $alias = null) + public function from(string $from, ?string $alias = null) { return $this->add('from', [ 'table' => $from, @@ -627,7 +623,7 @@ public function from($from, $alias = null) * * @return $this This QueryBuilder instance. */ - public function join($fromAlias, $join, $alias, $condition = null) + public function join(string $fromAlias, string $join, string $alias, ?string $condition = null) { return $this->innerJoin($fromAlias, $join, $alias, $condition); } @@ -649,7 +645,7 @@ public function join($fromAlias, $join, $alias, $condition = null) * * @return $this This QueryBuilder instance. */ - public function innerJoin($fromAlias, $join, $alias, $condition = null) + public function innerJoin(string $fromAlias, string $join, string $alias, ?string $condition = null) { return $this->add('join', [ $fromAlias => [ @@ -678,7 +674,7 @@ public function innerJoin($fromAlias, $join, $alias, $condition = null) * * @return $this This QueryBuilder instance. */ - public function leftJoin($fromAlias, $join, $alias, $condition = null) + public function leftJoin(string $fromAlias, string $join, string $alias, ?string $condition = null) { return $this->add('join', [ $fromAlias => [ @@ -707,7 +703,7 @@ public function leftJoin($fromAlias, $join, $alias, $condition = null) * * @return $this This QueryBuilder instance. */ - public function rightJoin($fromAlias, $join, $alias, $condition = null) + public function rightJoin(string $fromAlias, string $join, string $alias, ?string $condition = null) { return $this->add('join', [ $fromAlias => [ @@ -734,7 +730,7 @@ public function rightJoin($fromAlias, $join, $alias, $condition = null) * * @return $this This QueryBuilder instance. */ - public function set($key, $value) + public function set(string $key, string $value) { return $this->add('set', $key . ' = ' . $value, true); } @@ -855,7 +851,7 @@ public function orWhere($where) * * @return $this This QueryBuilder instance. */ - public function groupBy($groupBy) + public function groupBy($groupBy) : self { if (empty($groupBy)) { return $this; @@ -881,7 +877,7 @@ public function groupBy($groupBy) * * @return $this This QueryBuilder instance. */ - public function addGroupBy($groupBy) + public function addGroupBy($groupBy) : self { if (empty($groupBy)) { return $this; @@ -911,7 +907,7 @@ public function addGroupBy($groupBy) * * @return $this This QueryBuilder instance. */ - public function setValue($column, $value) + public function setValue(string $column, string $value) : self { $this->sqlParts['values'][$column] = $value; @@ -933,7 +929,7 @@ public function setValue($column, $value) * ); * * - * @param mixed[] $values The values to specify for the insert query indexed by column names. + * @param array $values The values to specify for the insert query indexed by column names. * * @return $this This QueryBuilder instance. */ @@ -1014,7 +1010,7 @@ public function orHaving($having) * * @return $this This QueryBuilder instance. */ - public function orderBy($sort, $order = null) + public function orderBy(string $sort, ?string $order = null) { return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), false); } @@ -1027,7 +1023,7 @@ public function orderBy($sort, $order = null) * * @return $this This QueryBuilder instance. */ - public function addOrderBy($sort, $order = null) + public function addOrderBy(string $sort, ?string $order = null) { return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), true); } @@ -1035,11 +1031,9 @@ public function addOrderBy($sort, $order = null) /** * Gets a query part by its name. * - * @param string $queryPartName - * * @return mixed */ - public function getQueryPart($queryPartName) + public function getQueryPart(string $queryPartName) { return $this->sqlParts[$queryPartName]; } @@ -1047,9 +1041,9 @@ public function getQueryPart($queryPartName) /** * Gets all query parts. * - * @return mixed[] + * @return array */ - public function getQueryParts() + public function getQueryParts() : array { return $this->sqlParts; } @@ -1057,11 +1051,11 @@ public function getQueryParts() /** * Resets SQL parts. * - * @param string[]|null $queryPartNames + * @param array|null $queryPartNames * * @return $this This QueryBuilder instance. */ - public function resetQueryParts($queryPartNames = null) + public function resetQueryParts(?array $queryPartNames = null) : self { if ($queryPartNames === null) { $queryPartNames = array_keys($this->sqlParts); @@ -1077,11 +1071,9 @@ public function resetQueryParts($queryPartNames = null) /** * Resets a single SQL part. * - * @param string $queryPartName - * * @return $this This QueryBuilder instance. */ - public function resetQueryPart($queryPartName) + public function resetQueryPart(string $queryPartName) : self { $this->sqlParts[$queryPartName] = is_array($this->sqlParts[$queryPartName]) ? [] : null; @@ -1092,11 +1084,9 @@ public function resetQueryPart($queryPartName) } /** - * @return string - * * @throws QueryException */ - private function getSQLForSelect() + private function getSQLForSelect() : string { $query = 'SELECT ' . implode(', ', $this->sqlParts['select']); @@ -1118,20 +1108,24 @@ private function getSQLForSelect() } /** - * @return string[] + * @return array */ - private function getFromClauses() + private function getFromClauses() : array { $fromClauses = []; $knownAliases = []; // Loop through all FROM clauses foreach ($this->sqlParts['from'] as $from) { - if ($from['alias'] === null) { - $tableSql = $from['table']; + if ($from['alias'] === null || $from['alias'] === $from['table']) { + $tableSql = $from['table']; + + /** @var string $tableReference */ $tableReference = $from['table']; } else { - $tableSql = $from['table'] . ' ' . $from['alias']; + $tableSql = $from['table'] . ' ' . $from['alias']; + + /** @var string $tableReference */ $tableReference = $from['alias']; } @@ -1146,33 +1140,28 @@ private function getFromClauses() } /** - * @param string[] $knownAliases + * @param array $knownAliases * * @throws QueryException */ - private function verifyAllAliasesAreKnown(array $knownAliases) + private function verifyAllAliasesAreKnown(array $knownAliases) : void { foreach ($this->sqlParts['join'] as $fromAlias => $joins) { if (! isset($knownAliases[$fromAlias])) { - throw QueryException::unknownAlias($fromAlias, array_keys($knownAliases)); + throw UnknownAlias::new($fromAlias, array_keys($knownAliases)); } } } - /** - * @return bool - */ - private function isLimitQuery() + private function isLimitQuery() : bool { - return $this->maxResults !== null || $this->firstResult !== null; + return $this->maxResults !== null || $this->firstResult !== 0; } /** * Converts this instance into an INSERT string in SQL. - * - * @return string */ - private function getSQLForInsert() + private function getSQLForInsert() : string { return 'INSERT INTO ' . $this->sqlParts['from']['table'] . ' (' . implode(', ', array_keys($this->sqlParts['values'])) . ')' . @@ -1181,12 +1170,16 @@ private function getSQLForInsert() /** * Converts this instance into an UPDATE string in SQL. - * - * @return string */ - private function getSQLForUpdate() + private function getSQLForUpdate() : string { - $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $from = $this->sqlParts['from']; + + if ($from['alias'] === null || $from['alias'] === $from['table']) { + $table = $from['table']; + } else { + $table = $from['table'] . ' ' . $from['alias']; + } return 'UPDATE ' . $table . ' SET ' . implode(', ', $this->sqlParts['set']) @@ -1195,12 +1188,16 @@ private function getSQLForUpdate() /** * Converts this instance into a DELETE string in SQL. - * - * @return string */ - private function getSQLForDelete() + private function getSQLForDelete() : string { - $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $from = $this->sqlParts['from']; + + if ($from['alias'] === null || $from['alias'] === $from['table']) { + $table = $from['table']; + } else { + $table = $from['table'] . ' ' . $from['alias']; + } return 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); } @@ -1211,7 +1208,7 @@ private function getSQLForDelete() * * @return string The string representation of this QueryBuilder. */ - public function __toString() + public function __toString() : string { return $this->getSQL(); } @@ -1244,7 +1241,7 @@ public function __toString() * * @return string the placeholder name used. */ - public function createNamedParameter($value, $type = ParameterType::STRING, $placeHolder = null) + public function createNamedParameter($value, $type = ParameterType::STRING, ?string $placeHolder = null) : string { if ($placeHolder === null) { $this->boundCounter++; @@ -1273,11 +1270,8 @@ public function createNamedParameter($value, $type = ParameterType::STRING, $pla * * * @param mixed $value - * @param int $type - * - * @return string */ - public function createPositionalParameter($value, $type = ParameterType::STRING) + public function createPositionalParameter($value, int $type = ParameterType::STRING) : string { $this->boundCounter++; $this->setParameter($this->boundCounter, $value, $type); @@ -1286,21 +1280,18 @@ public function createPositionalParameter($value, $type = ParameterType::STRING) } /** - * @param string $fromAlias - * @param string[] $knownAliases - * - * @return string + * @param array $knownAliases * * @throws QueryException */ - private function getSQLForJoins($fromAlias, array &$knownAliases) + private function getSQLForJoins(string $fromAlias, array &$knownAliases) : string { $sql = ''; if (isset($this->sqlParts['join'][$fromAlias])) { foreach ($this->sqlParts['join'][$fromAlias] as $join) { if (array_key_exists($join['joinAlias'], $knownAliases)) { - throw QueryException::nonUniqueAlias($join['joinAlias'], array_keys($knownAliases)); + throw NonUniqueAlias::new($join['joinAlias'], array_keys($knownAliases)); } $sql .= ' ' . strtoupper($join['joinType']) . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias'] @@ -1318,8 +1309,6 @@ private function getSQLForJoins($fromAlias, array &$knownAliases) /** * Deep clone of all expression objects in the SQL parts. - * - * @return void */ public function __clone() { diff --git a/lib/Doctrine/DBAL/Query/QueryException.php b/lib/Doctrine/DBAL/Query/QueryException.php index 3fcb3b480ec..de28829f8e5 100644 --- a/lib/Doctrine/DBAL/Query/QueryException.php +++ b/lib/Doctrine/DBAL/Query/QueryException.php @@ -1,35 +1,11 @@ matched fragment string, * 1 => offset of fragment in $statement * - * @param string $statement - * * @return mixed[][] */ - private static function getUnquotedStatementFragments($statement) + private static function getUnquotedStatementFragments(string $statement) : array { $literal = self::ESCAPED_SINGLE_QUOTED_TEXT . '|' . self::ESCAPED_DOUBLE_QUOTED_TEXT . '|' . @@ -260,14 +243,13 @@ private static function getUnquotedStatementFragments($statement) /** * @param string $paramName The name of the parameter (without a colon in front) * @param mixed $paramsOrTypes A hash of parameters or types - * @param bool $isParam * @param mixed $defaultValue An optional default value. If omitted, an exception is thrown * * @return mixed * * @throws SQLParserUtilsException */ - private static function extractParam($paramName, $paramsOrTypes, $isParam, $defaultValue = null) + private static function extractParam(string $paramName, $paramsOrTypes, bool $isParam, $defaultValue = null) { if (array_key_exists($paramName, $paramsOrTypes)) { return $paramsOrTypes[$paramName]; @@ -283,9 +265,9 @@ private static function extractParam($paramName, $paramsOrTypes, $isParam, $defa } if ($isParam) { - throw SQLParserUtilsException::missingParam($paramName); + throw MissingArrayParameter::new($paramName); } - throw SQLParserUtilsException::missingType($paramName); + throw MissingArrayParameterType::new($paramName); } } diff --git a/lib/Doctrine/DBAL/SQLParserUtilsException.php b/lib/Doctrine/DBAL/SQLParserUtilsException.php index a500ed52dd3..afb27530488 100644 --- a/lib/Doctrine/DBAL/SQLParserUtilsException.php +++ b/lib/Doctrine/DBAL/SQLParserUtilsException.php @@ -1,31 +1,12 @@ isIdentifierQuoted($name)) { $this->_quoted = true; @@ -58,12 +56,8 @@ protected function _setName($name) /** * Is this asset in the default namespace? - * - * @param string $defaultNamespaceName - * - * @return bool */ - public function isInDefaultNamespace($defaultNamespaceName) + public function isInDefaultNamespace(string $defaultNamespaceName) : bool { return $this->_namespace === $defaultNamespaceName || $this->_namespace === null; } @@ -72,10 +66,8 @@ public function isInDefaultNamespace($defaultNamespaceName) * Gets the namespace name of this asset. * * If NULL is returned this means the default namespace is used. - * - * @return string|null */ - public function getNamespaceName() + public function getNamespaceName() : ?string { return $this->_namespace; } @@ -83,12 +75,8 @@ public function getNamespaceName() /** * The shortest name is stripped of the default namespace. All other * namespaced elements are returned as full-qualified names. - * - * @param string|null $defaultNamespaceName - * - * @return string */ - public function getShortestName($defaultNamespaceName) + public function getShortestName(?string $defaultNamespaceName) : string { $shortestName = $this->getName(); if ($this->_namespace === $defaultNamespaceName) { @@ -106,12 +94,8 @@ public function getShortestName($defaultNamespaceName) * * Every non-namespaced element is prefixed with the default namespace * name which is passed as argument to this method. - * - * @param string $defaultNamespaceName - * - * @return string */ - public function getFullQualifiedName($defaultNamespaceName) + public function getFullQualifiedName(string $defaultNamespaceName) : string { $name = $this->getName(); if (! $this->_namespace) { @@ -123,44 +107,32 @@ public function getFullQualifiedName($defaultNamespaceName) /** * Checks if this asset's name is quoted. - * - * @return bool */ - public function isQuoted() + public function isQuoted() : bool { return $this->_quoted; } /** * Checks if this identifier is quoted. - * - * @param string $identifier - * - * @return bool */ - protected function isIdentifierQuoted($identifier) + protected function isIdentifierQuoted(string $identifier) : bool { return isset($identifier[0]) && ($identifier[0] === '`' || $identifier[0] === '"' || $identifier[0] === '['); } /** * Trim quotes from the identifier. - * - * @param string $identifier - * - * @return string */ - protected function trimQuotes($identifier) + protected function trimQuotes(string $identifier) : string { return str_replace(['`', '"', '[', ']'], '', $identifier); } /** * Returns the name of this schema asset. - * - * @return string */ - public function getName() + public function getName() : string { if ($this->_namespace) { return $this->_namespace . '.' . $this->_name; @@ -172,10 +144,8 @@ public function getName() /** * Gets the quoted representation of this asset but only if it was defined with one. Otherwise * return the plain unquoted value as inserted. - * - * @return string */ - public function getQuotedName(AbstractPlatform $platform) + public function getQuotedName(AbstractPlatform $platform) : string { $keywords = $platform->getReservedKeywordsList(); $parts = explode('.', $this->getName()); @@ -193,15 +163,11 @@ public function getQuotedName(AbstractPlatform $platform) * however building idents automatically for foreign keys, composite keys or such can easily create * very long names. * - * @param string[] $columnNames - * @param string $prefix - * @param int $maxSize - * - * @return string + * @param array $columnNames */ - protected function _generateIdentifierName($columnNames, $prefix = '', $maxSize = 30) + protected function _generateIdentifierName(array $columnNames, string $prefix = '', int $maxSize = 30) : string { - $hash = implode('', array_map(static function ($column) { + $hash = implode('', array_map(static function ($column) : string { return dechex(crc32($column)); }, $columnNames)); diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 5c92c2e3f7b..659648b674c 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -1,5 +1,7 @@ _platform; } @@ -95,9 +97,9 @@ public function tryMethod() /** * Lists the available databases for this connection. * - * @return string[] + * @return array */ - public function listDatabases() + public function listDatabases() : array { $sql = $this->_platform->getListDatabasesSQL(); @@ -109,9 +111,9 @@ public function listDatabases() /** * Returns a list of all namespaces in the current database. * - * @return string[] + * @return array */ - public function listNamespaceNames() + public function listNamespaceNames() : array { $sql = $this->_platform->getListNamespacesSQL(); @@ -123,15 +125,15 @@ public function listNamespaceNames() /** * Lists the available sequences for this connection. * - * @param string|null $database - * - * @return Sequence[] + * @return array */ - public function listSequences($database = null) + public function listSequences(?string $database = null) : array { - if ($database === null) { - $database = $this->_conn->getDatabase(); - } + $database = $this->ensureDatabase( + $database ?? $this->_conn->getDatabase(), + __METHOD__ + ); + $sql = $this->_platform->getListSequencesSQL($database); $sequences = $this->_conn->fetchAll($sql); @@ -149,16 +151,14 @@ public function listSequences($database = null) * of a table. We're a RDBMS specifies more details these are held * in the platformDetails array. * - * @param string $table The name of the table. - * @param string|null $database - * - * @return Column[] + * @return array */ - public function listTableColumns($table, $database = null) + public function listTableColumns(string $table, ?string $database = null) : array { - if (! $database) { - $database = $this->_conn->getDatabase(); - } + $database = $this->ensureDatabase( + $database ?? $this->_conn->getDatabase(), + __METHOD__ + ); $sql = $this->_platform->getListTableColumnsSQL($table, $database); @@ -172,11 +172,9 @@ public function listTableColumns($table, $database = null) * * Keys of the portable indexes list are all lower-cased. * - * @param string $table The name of the table. - * - * @return Index[] + * @return array */ - public function listTableIndexes($table) + public function listTableIndexes(string $table) : array { $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); @@ -188,23 +186,26 @@ public function listTableIndexes($table) /** * Returns true if all the given tables exist. * - * @param string|string[] $tableNames - * - * @return bool + * @param array $tableNames */ - public function tablesExist($tableNames) + public function tablesExist(array $tableNames) : bool { - $tableNames = array_map('strtolower', (array) $tableNames); + $tableNames = array_map('strtolower', $tableNames); return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames()))); } + public function tableExists(string $tableName) : bool + { + return $this->tablesExist([$tableName]); + } + /** * Returns a list of all tables in the current database. * - * @return string[] + * @return array */ - public function listTableNames() + public function listTableNames() : array { $sql = $this->_platform->getListTablesSQL(); @@ -218,11 +219,11 @@ public function listTableNames() * Filters asset names if they are configured to return only a subset of all * the found elements. * - * @param mixed[] $assetNames + * @param array $assetNames * - * @return mixed[] + * @return array */ - protected function filterAssetNames($assetNames) + protected function filterAssetNames(array $assetNames) : array { $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter(); if (! $filter) { @@ -232,22 +233,12 @@ protected function filterAssetNames($assetNames) return array_values(array_filter($assetNames, $filter)); } - /** - * @deprecated Use Configuration::getSchemaAssetsFilter() instead - * - * @return string|null - */ - protected function getFilterSchemaAssetsExpression() - { - return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression(); - } - /** * Lists the tables for this connection. * - * @return Table[] + * @return array */ - public function listTables() + public function listTables() : array { $tableNames = $this->listTableNames(); @@ -259,33 +250,34 @@ public function listTables() return $tables; } - /** - * @param string $tableName - * - * @return Table - */ - public function listTableDetails($tableName) + public function listTableDetails(string $tableName) : Table { $columns = $this->listTableColumns($tableName); $foreignKeys = []; + if ($this->_platform->supportsForeignKeyConstraints()) { $foreignKeys = $this->listTableForeignKeys($tableName); } + $indexes = $this->listTableIndexes($tableName); - return new Table($tableName, $columns, $indexes, $foreignKeys); + return new Table($tableName, $columns, $indexes, [], $foreignKeys, []); } /** * Lists the views this connection has. * - * @return View[] + * @return array */ - public function listViews() + public function listViews() : array { - $database = $this->_conn->getDatabase(); - $sql = $this->_platform->getListViewsSQL($database); - $views = $this->_conn->fetchAll($sql); + $database = $this->ensureDatabase( + $this->_conn->getDatabase(), + __METHOD__ + ); + + $sql = $this->_platform->getListViewsSQL($database); + $views = $this->_conn->fetchAll($sql); return $this->_getPortableViewsList($views); } @@ -293,12 +285,9 @@ public function listViews() /** * Lists the foreign keys for the given table. * - * @param string $table The name of the table. - * @param string|null $database - * - * @return ForeignKeyConstraint[] + * @return array */ - public function listTableForeignKeys($table, $database = null) + public function listTableForeignKeys(string $table, ?string $database = null) : array { if ($database === null) { $database = $this->_conn->getDatabase(); @@ -315,24 +304,16 @@ public function listTableForeignKeys($table, $database = null) * Drops a database. * * NOTE: You can not drop the database this SchemaManager is currently connected to. - * - * @param string $database The name of the database to drop. - * - * @return void */ - public function dropDatabase($database) + public function dropDatabase(string $database) : void { $this->_execSql($this->_platform->getDropDatabaseSQL($database)); } /** * Drops the given table. - * - * @param string $tableName The name of the table to drop. - * - * @return void */ - public function dropTable($tableName) + public function dropTable(string $tableName) : void { $this->_execSql($this->_platform->getDropTableSQL($tableName)); } @@ -342,10 +323,8 @@ public function dropTable($tableName) * * @param Index|string $index The name of the index. * @param Table|string $table The name of the table. - * - * @return void */ - public function dropIndex($index, $table) + public function dropIndex($index, $table) : void { if ($index instanceof Index) { $index = $index->getQuotedName($this->_platform); @@ -358,10 +337,8 @@ public function dropIndex($index, $table) * Drops the constraint from the given table. * * @param Table|string $table The name of the table. - * - * @return void */ - public function dropConstraint(Constraint $constraint, $table) + public function dropConstraint(Constraint $constraint, $table) : void { $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table)); } @@ -371,34 +348,24 @@ public function dropConstraint(Constraint $constraint, $table) * * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key. * @param Table|string $table The name of the table with the foreign key. - * - * @return void */ - public function dropForeignKey($foreignKey, $table) + public function dropForeignKey($foreignKey, $table) : void { $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table)); } /** * Drops a sequence with a given name. - * - * @param string $name The name of the sequence to drop. - * - * @return void */ - public function dropSequence($name) + public function dropSequence(string $name) : void { $this->_execSql($this->_platform->getDropSequenceSQL($name)); } /** * Drops a view. - * - * @param string $name The name of the view. - * - * @return void */ - public function dropView($name) + public function dropView(string $name) : void { $this->_execSql($this->_platform->getDropViewSQL($name)); } @@ -407,22 +374,16 @@ public function dropView($name) /** * Creates a new database. - * - * @param string $database The name of the database to create. - * - * @return void */ - public function createDatabase($database) + public function createDatabase(string $database) : void { $this->_execSql($this->_platform->getCreateDatabaseSQL($database)); } /** * Creates a new table. - * - * @return void */ - public function createTable(Table $table) + public function createTable(Table $table) : void { $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS; $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags)); @@ -431,13 +392,9 @@ public function createTable(Table $table) /** * Creates a new sequence. * - * @param Sequence $sequence - * - * @return void - * * @throws ConnectionException If something fails at database level. */ - public function createSequence($sequence) + public function createSequence(Sequence $sequence) : void { $this->_execSql($this->_platform->getCreateSequenceSQL($sequence)); } @@ -446,10 +403,8 @@ public function createSequence($sequence) * Creates a constraint on a table. * * @param Table|string $table - * - * @return void */ - public function createConstraint(Constraint $constraint, $table) + public function createConstraint(Constraint $constraint, $table) : void { $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table)); } @@ -458,10 +413,8 @@ public function createConstraint(Constraint $constraint, $table) * Creates a new index on a table. * * @param Table|string $table The name of the table on which the index is to be created. - * - * @return void */ - public function createIndex(Index $index, $table) + public function createIndex(Index $index, $table) : void { $this->_execSql($this->_platform->getCreateIndexSQL($index, $table)); } @@ -471,20 +424,16 @@ public function createIndex(Index $index, $table) * * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. * @param Table|string $table The name of the table on which the foreign key is to be created. - * - * @return void */ - public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) + public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void { $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table)); } /** * Creates a new view. - * - * @return void */ - public function createView(View $view) + public function createView(View $view) : void { $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql())); } @@ -498,10 +447,8 @@ public function createView(View $view) * @see createConstraint() * * @param Table|string $table - * - * @return void */ - public function dropAndCreateConstraint(Constraint $constraint, $table) + public function dropAndCreateConstraint(Constraint $constraint, $table) : void { $this->tryMethod('dropConstraint', $constraint, $table); $this->createConstraint($constraint, $table); @@ -511,10 +458,8 @@ public function dropAndCreateConstraint(Constraint $constraint, $table) * Drops and creates a new index on a table. * * @param Table|string $table The name of the table on which the index is to be created. - * - * @return void */ - public function dropAndCreateIndex(Index $index, $table) + public function dropAndCreateIndex(Index $index, $table) : void { $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table); $this->createIndex($index, $table); @@ -525,10 +470,8 @@ public function dropAndCreateIndex(Index $index, $table) * * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created. * @param Table|string $table The name of the table on which the foreign key is to be created. - * - * @return void */ - public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) : void { $this->tryMethod('dropForeignKey', $foreignKey, $table); $this->createForeignKey($foreignKey, $table); @@ -537,11 +480,9 @@ public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table /** * Drops and create a new sequence. * - * @return void - * * @throws ConnectionException If something fails at database level. */ - public function dropAndCreateSequence(Sequence $sequence) + public function dropAndCreateSequence(Sequence $sequence) : void { $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform)); $this->createSequence($sequence); @@ -549,10 +490,8 @@ public function dropAndCreateSequence(Sequence $sequence) /** * Drops and creates a new table. - * - * @return void */ - public function dropAndCreateTable(Table $table) + public function dropAndCreateTable(Table $table) : void { $this->tryMethod('dropTable', $table->getQuotedName($this->_platform)); $this->createTable($table); @@ -560,12 +499,8 @@ public function dropAndCreateTable(Table $table) /** * Drops and creates a new database. - * - * @param string $database The name of the database to create. - * - * @return void */ - public function dropAndCreateDatabase($database) + public function dropAndCreateDatabase(string $database) : void { $this->tryMethod('dropDatabase', $database); $this->createDatabase($database); @@ -573,10 +508,8 @@ public function dropAndCreateDatabase($database) /** * Drops and creates a new view. - * - * @return void */ - public function dropAndCreateView(View $view) + public function dropAndCreateView(View $view) : void { $this->tryMethod('dropView', $view->getQuotedName($this->_platform)); $this->createView($view); @@ -586,12 +519,11 @@ public function dropAndCreateView(View $view) /** * Alters an existing tables schema. - * - * @return void */ - public function alterTable(TableDiff $tableDiff) + public function alterTable(TableDiff $tableDiff) : void { $queries = $this->_platform->getAlterTableSQL($tableDiff); + if (! is_array($queries) || ! count($queries)) { return; } @@ -603,13 +535,8 @@ public function alterTable(TableDiff $tableDiff) /** * Renames a given table to another name. - * - * @param string $name The current name of the table. - * @param string $newName The new name of the table. - * - * @return void */ - public function renameTable($name, $newName) + public function renameTable(string $name, string $newName) : void { $tableDiff = new TableDiff($name); $tableDiff->newName = $newName; @@ -622,11 +549,11 @@ public function renameTable($name, $newName) */ /** - * @param mixed[] $databases + * @param array $databases * - * @return string[] + * @return array */ - protected function _getPortableDatabasesList($databases) + protected function _getPortableDatabasesList(array $databases) : array { $list = []; foreach ($databases as $value) { @@ -645,11 +572,11 @@ protected function _getPortableDatabasesList($databases) /** * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition. * - * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition. + * @param array> $namespaces The list of namespace names in the native DBMS data definition. * - * @return string[] + * @return array */ - protected function getPortableNamespacesList(array $namespaces) + protected function getPortableNamespacesList(array $namespaces) : array { $namespacesList = []; @@ -661,95 +588,29 @@ protected function getPortableNamespacesList(array $namespaces) } /** - * @param mixed $database - * - * @return mixed + * @param array $database */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { - return $database; + return array_shift($database); } /** * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition. * - * @param mixed[] $namespace The native DBMS namespace definition. - * - * @return mixed + * @param array $namespace The native DBMS namespace definition. */ - protected function getPortableNamespaceDefinition(array $namespace) + protected function getPortableNamespaceDefinition(array $namespace) : string { - return $namespace; + return array_shift($namespace); } /** - * @param mixed[][] $functions + * @param array> $sequences * - * @return mixed[][] + * @return array */ - protected function _getPortableFunctionsList($functions) - { - $list = []; - foreach ($functions as $value) { - $value = $this->_getPortableFunctionDefinition($value); - - if (! $value) { - continue; - } - - $list[] = $value; - } - - return $list; - } - - /** - * @param mixed[] $function - * - * @return mixed - */ - protected function _getPortableFunctionDefinition($function) - { - return $function; - } - - /** - * @param mixed[][] $triggers - * - * @return mixed[][] - */ - protected function _getPortableTriggersList($triggers) - { - $list = []; - foreach ($triggers as $value) { - $value = $this->_getPortableTriggerDefinition($value); - - if (! $value) { - continue; - } - - $list[] = $value; - } - - return $list; - } - - /** - * @param mixed[] $trigger - * - * @return mixed - */ - protected function _getPortableTriggerDefinition($trigger) - { - return $trigger; - } - - /** - * @param mixed[][] $sequences - * - * @return Sequence[] - */ - protected function _getPortableSequencesList($sequences) + protected function _getPortableSequencesList(array $sequences) : array { $list = []; @@ -761,15 +622,13 @@ protected function _getPortableSequencesList($sequences) } /** - * @param mixed[] $sequence - * - * @return Sequence + * @param array $sequence * * @throws DBALException */ - protected function _getPortableSequenceDefinition($sequence) + protected function _getPortableSequenceDefinition(array $sequence) : Sequence { - throw DBALException::notSupported('Sequences'); + throw NotSupported::new('Sequences'); } /** @@ -777,13 +636,11 @@ protected function _getPortableSequenceDefinition($sequence) * * The name of the created column instance however is kept in its case. * - * @param string $table The name of the table. - * @param string $database - * @param mixed[][] $tableColumns + * @param array> $tableColumns * - * @return Column[] + * @return array */ - protected function _getPortableTableColumnList($table, $database, $tableColumns) + protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns) : array { $eventManager = $this->_platform->getEventManager(); @@ -818,21 +675,18 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns) /** * Gets Table Column Definition. * - * @param mixed[] $tableColumn - * - * @return Column + * @param array $tableColumn */ - abstract protected function _getPortableTableColumnDefinition($tableColumn); + abstract protected function _getPortableTableColumnDefinition(array $tableColumn) : Column; /** * Aggregates and groups the index results according to the required data result. * - * @param mixed[][] $tableIndexRows - * @param string|null $tableName + * @param array> $tableIndexRows * - * @return Index[] + * @return array */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $result = []; foreach ($tableIndexRows as $tableIndex) { @@ -895,11 +749,11 @@ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = nu } /** - * @param mixed[][] $tables + * @param array> $tables * - * @return string[] + * @return array */ - protected function _getPortableTablesList($tables) + protected function _getPortableTablesList(array $tables) : array { $list = []; foreach ($tables as $value) { @@ -916,21 +770,19 @@ protected function _getPortableTablesList($tables) } /** - * @param mixed $table - * - * @return string + * @param array $table */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { - return $table; + return array_shift($table); } /** - * @param mixed[][] $users + * @param array> $users * - * @return string[][] + * @return array> */ - protected function _getPortableUsersList($users) + protected function _getPortableUsersList(array $users) : array { $list = []; foreach ($users as $value) { @@ -947,53 +799,46 @@ protected function _getPortableUsersList($users) } /** - * @param string[] $user + * @param array $user * - * @return string[] + * @return array */ - protected function _getPortableUserDefinition($user) + protected function _getPortableUserDefinition(array $user) : array { return $user; } /** - * @param mixed[][] $views + * @param array> $views * - * @return View[] + * @return array */ - protected function _getPortableViewsList($views) + protected function _getPortableViewsList(array $views) : array { $list = []; foreach ($views as $value) { - $view = $this->_getPortableViewDefinition($value); - - if (! $view) { - continue; - } - - $viewName = strtolower($view->getQuotedName($this->_platform)); - $list[$viewName] = $view; + $view = $this->_getPortableViewDefinition($value); + $name = strtolower($view->getQuotedName($this->_platform)); + $list[$name] = $view; } return $list; } /** - * @param mixed[] $view - * - * @return View|false + * @param array $view */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { - return false; + throw NotSupported::new('Views'); } /** - * @param mixed[][] $tableForeignKeys + * @param array> $tableForeignKeys * - * @return ForeignKeyConstraint[] + * @return array */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $list = []; @@ -1005,21 +850,17 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) } /** - * @param mixed $tableForeignKey - * - * @return ForeignKeyConstraint + * @param array $tableForeignKey */ - protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint { - return $tableForeignKey; + throw NotSupported::new('ForeignKey'); } /** - * @param string[]|string $sql - * - * @return void + * @param array|string $sql */ - protected function _execSql($sql) + protected function _execSql($sql) : void { foreach ((array) $sql as $query) { $this->_conn->executeUpdate($query); @@ -1028,10 +869,8 @@ protected function _execSql($sql) /** * Creates a schema instance for the current database. - * - * @return Schema */ - public function createSchema() + public function createSchema() : Schema { $namespaces = []; @@ -1052,10 +891,8 @@ public function createSchema() /** * Creates the configuration for this schema. - * - * @return SchemaConfig */ - public function createSchemaConfig() + public function createSchemaConfig() : SchemaConfig { $schemaConfig = new SchemaConfig(); $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); @@ -1087,43 +924,45 @@ public function createSchemaConfig() * For databases that don't support subschema/namespaces this method * returns the name of the currently connected database. * - * @return string[] + * @return array */ - public function getSchemaSearchPaths() + public function getSchemaSearchPaths() : array { - return [$this->_conn->getDatabase()]; + $database = $this->_conn->getDatabase(); + + if ($database !== null) { + return [$database]; + } + + return []; } /** - * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns - * the type given as default. - * - * @param string|null $comment - * @param string $currentType + * Given a table comment this method tries to extract a type hint for Doctrine Type. If the type hint is found, + * it's removed from the comment. * - * @return string + * @return string|null The extracted Doctrine type or NULL of the type hint was not found. */ - public function extractDoctrineTypeFromComment($comment, $currentType) + final protected function extractDoctrineTypeFromComment(?string &$comment) : ?string { - if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) { - return $match[1]; + if ($comment === null || ! preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match)) { + return null; } - return $currentType; + $comment = $match[1] . $match[4]; + + return $match[2]; } /** - * @param string|null $comment - * @param string|null $type - * - * @return string|null + * @throws DatabaseRequired */ - public function removeDoctrineTypeFromComment($comment, $type) + private function ensureDatabase(?string $database, string $methodName) : string { - if ($comment === null) { - return null; + if ($database === null) { + throw DatabaseRequired::new($methodName); } - return str_replace('(DC2Type:' . $type . ')', '', $comment); + return $database; } } diff --git a/lib/Doctrine/DBAL/Schema/Column.php b/lib/Doctrine/DBAL/Schema/Column.php index 56c39c14994..ea90241b419 100644 --- a/lib/Doctrine/DBAL/Schema/Column.php +++ b/lib/Doctrine/DBAL/Schema/Column.php @@ -1,11 +1,12 @@ */ protected $_platformOptions = []; /** @var string|null */ - protected $_columnDefinition = null; + protected $_columnDefinition; /** @var string|null */ - protected $_comment = null; + protected $_comment; - /** @var mixed[] */ + /** @var array */ protected $_customSchemaOptions = []; /** * Creates a new Column. * - * @param string $columnName - * @param mixed[] $options + * @param array $options */ - public function __construct($columnName, Type $type, array $options = []) + public function __construct(string $name, Type $type, array $options = []) { - $this->_setName($columnName); + $this->_setName($name); $this->setType($type); $this->setOptions($options); } /** - * @param mixed[] $options - * - * @return Column + * @param array $options */ - public function setOptions(array $options) + public function setOptions(array $options) : self { foreach ($options as $name => $value) { $method = 'set' . $name; @@ -92,106 +90,59 @@ public function setOptions(array $options) return $this; } - /** - * @return Column - */ - public function setType(Type $type) + public function setType(Type $type) : self { $this->_type = $type; return $this; } - /** - * @param int|null $length - * - * @return Column - */ - public function setLength($length) + public function setLength(?int $length) : self { - if ($length !== null) { - $this->_length = (int) $length; - } else { - $this->_length = null; - } + $this->_length = $length; return $this; } - /** - * @param int $precision - * - * @return Column - */ - public function setPrecision($precision) + public function setPrecision(?int $precision) : self { - if (! is_numeric($precision)) { - $precision = 10; // defaults to 10 when no valid precision is given. - } - - $this->_precision = (int) $precision; + $this->_precision = $precision; return $this; } - /** - * @param int $scale - * - * @return Column - */ - public function setScale($scale) + public function setScale(int $scale) : self { - if (! is_numeric($scale)) { - $scale = 0; - } - - $this->_scale = (int) $scale; + $this->_scale = $scale; return $this; } - /** - * @param bool $unsigned - * - * @return Column - */ - public function setUnsigned($unsigned) + public function setUnsigned(bool $unsigned) : self { - $this->_unsigned = (bool) $unsigned; + $this->_unsigned = $unsigned; return $this; } - /** - * @param bool $fixed - * - * @return Column - */ - public function setFixed($fixed) + public function setFixed(bool $fixed) : self { - $this->_fixed = (bool) $fixed; + $this->_fixed = $fixed; return $this; } - /** - * @param bool $notnull - * - * @return Column - */ - public function setNotnull($notnull) + public function setNotnull(bool $notnull) : self { - $this->_notnull = (bool) $notnull; + $this->_notnull = $notnull; return $this; } /** * @param mixed $default - * - * @return Column */ - public function setDefault($default) + public function setDefault($default) : self { $this->_default = $default; @@ -199,11 +150,9 @@ public function setDefault($default) } /** - * @param mixed[] $platformOptions - * - * @return Column + * @param array $platformOptions */ - public function setPlatformOptions(array $platformOptions) + public function setPlatformOptions(array $platformOptions) : self { $this->_platformOptions = $platformOptions; @@ -211,88 +160,59 @@ public function setPlatformOptions(array $platformOptions) } /** - * @param string $name - * @param mixed $value - * - * @return Column + * @param mixed $value */ - public function setPlatformOption($name, $value) + public function setPlatformOption(string $name, $value) : self { $this->_platformOptions[$name] = $value; return $this; } - /** - * @param string $value - * - * @return Column - */ - public function setColumnDefinition($value) + public function setColumnDefinition(string $value) : self { $this->_columnDefinition = $value; return $this; } - /** - * @return Type - */ - public function getType() + public function getType() : Type { return $this->_type; } - /** - * @return int|null - */ - public function getLength() + public function getLength() : ?int { return $this->_length; } - /** - * @return int - */ - public function getPrecision() + public function getPrecision() : ?int { return $this->_precision; } - /** - * @return int - */ - public function getScale() + public function getScale() : int { return $this->_scale; } - /** - * @return bool - */ - public function getUnsigned() + public function getUnsigned() : bool { return $this->_unsigned; } - /** - * @return bool - */ - public function getFixed() + public function getFixed() : bool { return $this->_fixed; } - /** - * @return bool - */ - public function getNotnull() + public function getNotnull() : bool { return $this->_notnull; } /** - * @return string|null + * @return mixed */ public function getDefault() { @@ -300,120 +220,82 @@ public function getDefault() } /** - * @return mixed[] + * @return array */ - public function getPlatformOptions() + public function getPlatformOptions() : array { return $this->_platformOptions; } - /** - * @param string $name - * - * @return bool - */ - public function hasPlatformOption($name) + public function hasPlatformOption(string $name) : bool { return isset($this->_platformOptions[$name]); } /** - * @param string $name - * * @return mixed */ - public function getPlatformOption($name) + public function getPlatformOption(string $name) { return $this->_platformOptions[$name]; } - /** - * @return string|null - */ - public function getColumnDefinition() + public function getColumnDefinition() : ?string { return $this->_columnDefinition; } - /** - * @return bool - */ - public function getAutoincrement() + public function getAutoincrement() : bool { return $this->_autoincrement; } - /** - * @param bool $flag - * - * @return Column - */ - public function setAutoincrement($flag) + public function setAutoincrement(bool $flag) : self { $this->_autoincrement = $flag; return $this; } - /** - * @param string|null $comment - * - * @return Column - */ - public function setComment($comment) + public function setComment(?string $comment) : self { $this->_comment = $comment; return $this; } - /** - * @return string|null - */ - public function getComment() + public function getComment() : ?string { return $this->_comment; } /** - * @param string $name - * @param mixed $value - * - * @return Column + * @param mixed $value */ - public function setCustomSchemaOption($name, $value) + public function setCustomSchemaOption(string $name, $value) : self { $this->_customSchemaOptions[$name] = $value; return $this; } - /** - * @param string $name - * - * @return bool - */ - public function hasCustomSchemaOption($name) + public function hasCustomSchemaOption(string $name) : bool { return isset($this->_customSchemaOptions[$name]); } /** - * @param string $name - * * @return mixed */ - public function getCustomSchemaOption($name) + public function getCustomSchemaOption(string $name) { return $this->_customSchemaOptions[$name]; } /** - * @param mixed[] $customSchemaOptions - * - * @return Column + * @param array $customSchemaOptions */ - public function setCustomSchemaOptions(array $customSchemaOptions) + public function setCustomSchemaOptions(array $customSchemaOptions) : self { $this->_customSchemaOptions = $customSchemaOptions; @@ -421,17 +303,17 @@ public function setCustomSchemaOptions(array $customSchemaOptions) } /** - * @return mixed[] + * @return array */ - public function getCustomSchemaOptions() + public function getCustomSchemaOptions() : array { return $this->_customSchemaOptions; } /** - * @return mixed[] + * @return array */ - public function toArray() + public function toArray() : array { return array_merge([ 'name' => $this->_name, diff --git a/lib/Doctrine/DBAL/Schema/ColumnDiff.php b/lib/Doctrine/DBAL/Schema/ColumnDiff.php index 1589f98d4a9..14c0d78ed92 100644 --- a/lib/Doctrine/DBAL/Schema/ColumnDiff.php +++ b/lib/Doctrine/DBAL/Schema/ColumnDiff.php @@ -1,5 +1,7 @@ */ public $changedProperties = []; /** @var Column|null */ public $fromColumn; /** - * @param string $oldColumnName - * @param string[] $changedProperties + * @param array $changedProperties */ - public function __construct($oldColumnName, Column $column, array $changedProperties = [], ?Column $fromColumn = null) + public function __construct(string $oldColumnName, Column $column, array $changedProperties = [], ?Column $fromColumn = null) { $this->oldColumnName = $oldColumnName; $this->column = $column; @@ -33,20 +34,12 @@ public function __construct($oldColumnName, Column $column, array $changedProper $this->fromColumn = $fromColumn; } - /** - * @param string $propertyName - * - * @return bool - */ - public function hasChanged($propertyName) + public function hasChanged(string $propertyName) : bool { return in_array($propertyName, $this->changedProperties); } - /** - * @return Identifier - */ - public function getOldColumnName() + public function getOldColumnName() : Identifier { $quote = $this->fromColumn && $this->fromColumn->isQuoted(); diff --git a/lib/Doctrine/DBAL/Schema/Comparator.php b/lib/Doctrine/DBAL/Schema/Comparator.php index 84d7808abef..4ac73b822a1 100644 --- a/lib/Doctrine/DBAL/Schema/Comparator.php +++ b/lib/Doctrine/DBAL/Schema/Comparator.php @@ -1,5 +1,7 @@ fromSchema = $fromSchema; @@ -67,7 +63,7 @@ public function compare(Schema $fromSchema, Schema $toSchema) $diff->newTables[$tableName] = $toSchema->getTable($tableName); } else { $tableDifferences = $this->diffTable($fromSchema->getTable($tableName), $toSchema->getTable($tableName)); - if ($tableDifferences !== false) { + if ($tableDifferences !== null) { $diff->changedTables[$tableName] = $tableDifferences; } } @@ -150,13 +146,7 @@ public function compare(Schema $fromSchema, Schema $toSchema) return $diff; } - /** - * @param Schema $schema - * @param Sequence $sequence - * - * @return bool - */ - private function isAutoIncrementSequenceInSchema($schema, $sequence) + private function isAutoIncrementSequenceInSchema(Schema $schema, Sequence $sequence) : bool { foreach ($schema->getTables() as $table) { if ($sequence->isAutoIncrementsFor($table)) { @@ -167,10 +157,7 @@ private function isAutoIncrementSequenceInSchema($schema, $sequence) return false; } - /** - * @return bool - */ - public function diffSequence(Sequence $sequence1, Sequence $sequence2) + public function diffSequence(Sequence $sequence1, Sequence $sequence2) : bool { if ($sequence1->getAllocationSize() !== $sequence2->getAllocationSize()) { return true; @@ -183,10 +170,8 @@ public function diffSequence(Sequence $sequence1, Sequence $sequence2) * Returns the difference between the tables $table1 and $table2. * * If there are no differences this method returns the boolean false. - * - * @return TableDiff|false */ - public function diffTable(Table $table1, Table $table2) + public function diffTable(Table $table1, Table $table2) : ?TableDiff { $changes = 0; $tableDifferences = new TableDiff($table1->getName()); @@ -292,16 +277,14 @@ public function diffTable(Table $table1, Table $table2) $changes++; } - return $changes ? $tableDifferences : false; + return $changes ? $tableDifferences : null; } /** * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop * however ambiguities between different possibilities should not lead to renaming at all. - * - * @return void */ - private function detectColumnRenamings(TableDiff $tableDifferences) + private function detectColumnRenamings(TableDiff $tableDifferences) : void { $renameCandidates = []; foreach ($tableDifferences->addedColumns as $addedColumnName => $addedColumn) { @@ -338,10 +321,8 @@ private function detectColumnRenamings(TableDiff $tableDifferences) /** * Try to find indexes that only changed their name, rename operations maybe cheaper than add/drop * however ambiguities between different possibilities should not lead to renaming at all. - * - * @return void */ - private function detectIndexRenamings(TableDiff $tableDifferences) + private function detectIndexRenamings(TableDiff $tableDifferences) : void { $renameCandidates = []; @@ -382,10 +363,7 @@ private function detectIndexRenamings(TableDiff $tableDifferences) } } - /** - * @return bool - */ - public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2) + public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2) : bool { if (array_map('strtolower', $key1->getUnquotedLocalColumns()) !== array_map('strtolower', $key2->getUnquotedLocalColumns())) { return true; @@ -412,9 +390,9 @@ public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint * If there are differences this method returns $field2, otherwise the * boolean false. * - * @return string[] + * @return array */ - public function diffColumn(Column $column1, Column $column2) + public function diffColumn(Column $column1, Column $column2) : array { $properties1 = $column1->toArray(); $properties2 = $column2->toArray(); @@ -429,13 +407,6 @@ public function diffColumn(Column $column1, Column $column2) $changedProperties[] = $property; } - // This is a very nasty hack to make comparator work with the legacy json_array type, which should be killed in v3 - if ($this->isALegacyJsonComparison($properties1['type'], $properties2['type'])) { - array_shift($changedProperties); - - $changedProperties[] = 'comment'; - } - // Null values need to be checked additionally as they tell whether to create or drop a default value. // null != 0, null != false, null != '' etc. This affects platform's table alteration SQL generation. if (($properties1['default'] === null) !== ($properties2['default'] === null) @@ -446,10 +417,10 @@ public function diffColumn(Column $column1, Column $column2) if (($properties1['type'] instanceof Types\StringType && ! $properties1['type'] instanceof Types\GuidType) || $properties1['type'] instanceof Types\BinaryType ) { - // check if value of length is set at all, default value assumed otherwise. - $length1 = $properties1['length'] ?: 255; - $length2 = $properties2['length'] ?: 255; - if ($length1 !== $length2) { + if ((isset($properties1['length']) !== isset($properties2['length'])) + || (isset($properties1['length']) && isset($properties2['length']) + && $properties1['length'] !== $properties2['length']) + ) { $changedProperties[] = 'length'; } @@ -498,30 +469,13 @@ public function diffColumn(Column $column1, Column $column2) return array_unique($changedProperties); } - /** - * TODO: kill with fire on v3.0 - * - * @deprecated - */ - private function isALegacyJsonComparison(Types\Type $one, Types\Type $other) : bool - { - if (! $one instanceof Types\JsonType || ! $other instanceof Types\JsonType) { - return false; - } - - return ( ! $one instanceof Types\JsonArrayType && $other instanceof Types\JsonArrayType) - || ( ! $other instanceof Types\JsonArrayType && $one instanceof Types\JsonArrayType); - } - /** * Finds the difference between the indexes $index1 and $index2. * * Compares $index1 with $index2 and returns $index2 if there are any * differences or false in case there are no differences. - * - * @return bool */ - public function diffIndex(Index $index1, Index $index2) + public function diffIndex(Index $index1, Index $index2) : bool { return ! ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)); } diff --git a/lib/Doctrine/DBAL/Schema/Constraint.php b/lib/Doctrine/DBAL/Schema/Constraint.php index 65e239ec119..2c167b9de67 100644 --- a/lib/Doctrine/DBAL/Schema/Constraint.php +++ b/lib/Doctrine/DBAL/Schema/Constraint.php @@ -1,5 +1,7 @@ */ - public function getColumns(); + public function getColumns() : array; /** * Returns the quoted representation of the column names @@ -37,7 +33,7 @@ public function getColumns(); * * @param AbstractPlatform $platform The platform to use for quotation. * - * @return string[] + * @return array */ - public function getQuotedColumns(AbstractPlatform $platform); + public function getQuotedColumns(AbstractPlatform $platform) : array; } diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index 201d6015b96..a0d2312f285 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -1,5 +1,7 @@ _platform->getListTablesSQL(); - $sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')'; + $sql = $this->_platform->getListTablesSQL() . ' AND CREATOR = CURRENT_USER'; $tables = $this->_conn->fetchAll($sql); @@ -36,16 +37,13 @@ public function listTableNames() /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); - $length = null; - $fixed = null; - $scale = false; - $precision = false; - - $default = null; + $length = $precision = $default = null; + $scale = 0; + $fixed = false; if ($tableColumn['default'] !== null && $tableColumn['default'] !== 'NULL') { $default = $tableColumn['default']; @@ -55,17 +53,12 @@ protected function _getPortableTableColumnDefinition($tableColumn) } } - $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); - - if (isset($tableColumn['comment'])) { - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - } + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); switch (strtolower($tableColumn['typename'])) { case 'varchar': $length = $tableColumn['length']; - $fixed = false; break; case 'character': $length = $tableColumn['length']; @@ -85,12 +78,10 @@ protected function _getPortableTableColumnDefinition($tableColumn) $options = [ 'length' => $length, 'unsigned' => false, - 'fixed' => (bool) $fixed, + 'fixed' => $fixed, 'default' => $default, 'autoincrement' => (bool) $tableColumn['autoincrement'], - 'notnull' => (bool) ($tableColumn['nulls'] === 'N'), - 'scale' => null, - 'precision' => null, + 'notnull' => $tableColumn['nulls'] === 'N', 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, @@ -108,7 +99,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) /** * {@inheritdoc} */ - protected function _getPortableTablesList($tables) + protected function _getPortableTablesList(array $tables) : array { $tableNames = []; foreach ($tables as $tableRow) { @@ -122,7 +113,7 @@ protected function _getPortableTablesList($tables) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndexRow) { $tableIndexRow = array_change_key_case($tableIndexRow, CASE_LOWER); @@ -135,7 +126,7 @@ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = nu /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], @@ -149,7 +140,7 @@ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $foreignKeys = []; @@ -179,23 +170,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableForeignKeyRuleDef($def) - { - if ($def === 'C') { - return 'CASCADE'; - } - - if ($def === 'N') { - return 'SET NULL'; - } - - return null; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { $view = array_change_key_case($view, CASE_LOWER); // sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199 diff --git a/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php b/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php deleted file mode 100644 index c334db2797b..00000000000 --- a/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php +++ /dev/null @@ -1,103 +0,0 @@ -_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); - $tableColumn['COLUMN_COMMENT'] = $this->removeDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); - - $options = [ - 'notnull' => ! (bool) $tableColumn['IS_NULLABLE'], - 'length' => (int) $tableColumn['CHARACTER_MAXIMUM_LENGTH'], - 'default' => $tableColumn['COLUMN_DEFAULT'] ?? null, - 'autoincrement' => (bool) $tableColumn['IS_AUTO_INCREMENT'], - 'scale' => (int) $tableColumn['NUMERIC_SCALE'], - 'precision' => (int) $tableColumn['NUMERIC_PRECISION'], - 'comment' => isset($tableColumn['COLUMN_COMMENT']) && $tableColumn['COLUMN_COMMENT'] !== '' - ? $tableColumn['COLUMN_COMMENT'] - : null, - ]; - - $column = new Column($tableColumn['COLUMN_NAME'], Type::getType($type), $options); - - if (! empty($tableColumn['COLLATION_NAME'])) { - $column->setPlatformOption('collation', $tableColumn['COLLATION_NAME']); - } - - return $column; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableDatabaseDefinition($database) - { - return $database['SCHEMA_NAME']; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableTableDefinition($table) - { - return $table['TABLE_NAME']; - } - - /** - * {@inheritdoc} - */ - public function _getPortableTableForeignKeyDefinition($tableForeignKey) - { - $columns = []; - foreach (explode(',', $tableForeignKey['CONSTRAINT_COLUMNS']) as $value) { - $columns[] = trim($value, ' `'); - } - - $refColumns = []; - foreach (explode(',', $tableForeignKey['REFERENCED_TABLE_COLUMNS']) as $value) { - $refColumns[] = trim($value, ' `'); - } - - return new ForeignKeyConstraint( - $columns, - $tableForeignKey['REFERENCED_TABLE_NAME'], - $refColumns, - $tableForeignKey['CONSTRAINT_NAME'], - [ - 'onUpdate' => $tableForeignKey['UPDATE_RULE'], - 'onDelete' => $tableForeignKey['DELETE_RULE'], - ] - ); - } - - /** - * {@inheritdoc} - */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) - { - $indexes = []; - foreach ($tableIndexes as $k) { - $k['primary'] = (bool) $k['primary']; - $indexes[] = $k; - } - - return parent::_getPortableTableIndexesList($indexes, $tableName); - } -} diff --git a/lib/Doctrine/DBAL/Schema/Exception/ColumnAlreadyExists.php b/lib/Doctrine/DBAL/Schema/Exception/ColumnAlreadyExists.php new file mode 100644 index 00000000000..80abd19757d --- /dev/null +++ b/lib/Doctrine/DBAL/Schema/Exception/ColumnAlreadyExists.php @@ -0,0 +1,19 @@ +getName(), + implode(', ', $foreignKey->getColumns()), + $foreignKey->getForeignTableName(), + implode(', ', $foreignKey->getForeignColumns()) + ) + ); + } +} diff --git a/lib/Doctrine/DBAL/Schema/Exception/NamespaceAlreadyExists.php b/lib/Doctrine/DBAL/Schema/Exception/NamespaceAlreadyExists.php new file mode 100644 index 00000000000..15c08620b4c --- /dev/null +++ b/lib/Doctrine/DBAL/Schema/Exception/NamespaceAlreadyExists.php @@ -0,0 +1,19 @@ + Identifier) * - * @var Identifier[] + * @var array */ protected $_localColumnNames; @@ -40,33 +41,30 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint /** * Asset identifier instances of the referenced table column names the foreign key constraint is associated with. - * array($columnName => Identifier) * - * @var Identifier[] + * @var array */ protected $_foreignColumnNames; /** * Options associated with the foreign key constraint. * - * @var mixed[] + * @var array */ protected $_options; /** * Initializes the foreign key constraint. * - * @param string[] $localColumnNames Names of the referencing table columns. - * @param Table|string $foreignTableName Referenced table. - * @param string[] $foreignColumnNames Names of the referenced table columns. - * @param string|null $name Name of the foreign key constraint. - * @param mixed[] $options Options associated with the foreign key constraint. + * @param array $localColumnNames Names of the referencing table columns. + * @param Table|string $foreignTableName Referenced table. + * @param array $foreignColumnNames Names of the referenced table columns. + * @param string $name Name of the foreign key constraint. + * @param array $options Options associated with the foreign key constraint. */ - public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name = null, array $options = []) + public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, string $name = '', array $options = []) { - if ($name !== null) { - $this->_setName($name); - } + $this->_setName($name); $this->_localColumnNames = $this->createIdentifierMap($localColumnNames); @@ -81,16 +79,16 @@ public function __construct(array $localColumnNames, $foreignTableName, array $f } /** - * @param string[] $names + * @param array $names * - * @return Identifier[] + * @return array */ private function createIdentifierMap(array $names) : array { $identifiers = []; foreach ($names as $name) { - $identifiers[$name] = new Identifier($name); + $identifiers[$name] = new Identifier($name ?? ''); } return $identifiers; @@ -99,10 +97,8 @@ private function createIdentifierMap(array $names) : array /** * Returns the name of the referencing table * the foreign key constraint is associated with. - * - * @return string */ - public function getLocalTableName() + public function getLocalTableName() : string { return $this->_localTable->getName(); } @@ -110,20 +106,13 @@ public function getLocalTableName() /** * Sets the Table instance of the referencing table * the foreign key constraint is associated with. - * - * @param Table $table Instance of the referencing table. - * - * @return void */ - public function setLocalTable(Table $table) + public function setLocalTable(Table $table) : void { $this->_localTable = $table; } - /** - * @return Table - */ - public function getLocalTable() + public function getLocalTable() : Table { return $this->_localTable; } @@ -132,9 +121,9 @@ public function getLocalTable() * Returns the names of the referencing table columns * the foreign key constraint is associated with. * - * @return string[] + * @return array */ - public function getLocalColumns() + public function getLocalColumns() : array { return array_keys($this->_localColumnNames); } @@ -149,9 +138,9 @@ public function getLocalColumns() * * @param AbstractPlatform $platform The platform to use for quotation. * - * @return string[] + * @return array */ - public function getQuotedLocalColumns(AbstractPlatform $platform) + public function getQuotedLocalColumns(AbstractPlatform $platform) : array { $columns = []; @@ -165,9 +154,9 @@ public function getQuotedLocalColumns(AbstractPlatform $platform) /** * Returns unquoted representation of local table column names for comparison with other FK * - * @return string[] + * @return array */ - public function getUnquotedLocalColumns() + public function getUnquotedLocalColumns() : array { return array_map([$this, 'trimQuotes'], $this->getLocalColumns()); } @@ -175,9 +164,9 @@ public function getUnquotedLocalColumns() /** * Returns unquoted representation of foreign table column names for comparison with other FK * - * @return string[] + * @return array */ - public function getUnquotedForeignColumns() + public function getUnquotedForeignColumns() : array { return array_map([$this, 'trimQuotes'], $this->getForeignColumns()); } @@ -187,7 +176,7 @@ public function getUnquotedForeignColumns() * * @see getLocalColumns */ - public function getColumns() + public function getColumns() : array { return $this->getLocalColumns(); } @@ -204,9 +193,9 @@ public function getColumns() * * @param AbstractPlatform $platform The platform to use for quotation. * - * @return string[] + * @return array */ - public function getQuotedColumns(AbstractPlatform $platform) + public function getQuotedColumns(AbstractPlatform $platform) : array { return $this->getQuotedLocalColumns($platform); } @@ -214,20 +203,16 @@ public function getQuotedColumns(AbstractPlatform $platform) /** * Returns the name of the referenced table * the foreign key constraint is associated with. - * - * @return string */ - public function getForeignTableName() + public function getForeignTableName() : string { return $this->_foreignTableName->getName(); } /** * Returns the non-schema qualified foreign table name. - * - * @return string */ - public function getUnqualifiedForeignTableName() + public function getUnqualifiedForeignTableName() : string { $name = $this->_foreignTableName->getName(); $position = strrpos($name, '.'); @@ -248,10 +233,8 @@ public function getUnqualifiedForeignTableName() * Otherwise the plain unquoted value as inserted is returned. * * @param AbstractPlatform $platform The platform to use for quotation. - * - * @return string */ - public function getQuotedForeignTableName(AbstractPlatform $platform) + public function getQuotedForeignTableName(AbstractPlatform $platform) : string { return $this->_foreignTableName->getQuotedName($platform); } @@ -260,9 +243,9 @@ public function getQuotedForeignTableName(AbstractPlatform $platform) * Returns the names of the referenced table columns * the foreign key constraint is associated with. * - * @return string[] + * @return array */ - public function getForeignColumns() + public function getForeignColumns() : array { return array_keys($this->_foreignColumnNames); } @@ -277,9 +260,9 @@ public function getForeignColumns() * * @param AbstractPlatform $platform The platform to use for quotation. * - * @return string[] + * @return array */ - public function getQuotedForeignColumns(AbstractPlatform $platform) + public function getQuotedForeignColumns(AbstractPlatform $platform) : array { $columns = []; @@ -293,12 +276,8 @@ public function getQuotedForeignColumns(AbstractPlatform $platform) /** * Returns whether or not a given option * is associated with the foreign key constraint. - * - * @param string $name Name of the option to check. - * - * @return bool */ - public function hasOption($name) + public function hasOption(string $name) : bool { return isset($this->_options[$name]); } @@ -306,11 +285,9 @@ public function hasOption($name) /** * Returns an option associated with the foreign key constraint. * - * @param string $name Name of the option the foreign key constraint is associated with. - * * @return mixed */ - public function getOption($name) + public function getOption(string $name) { return $this->_options[$name]; } @@ -318,9 +295,9 @@ public function getOption($name) /** * Returns the options associated with the foreign key constraint. * - * @return mixed[] + * @return array */ - public function getOptions() + public function getOptions() : array { return $this->_options; } @@ -328,10 +305,8 @@ public function getOptions() /** * Returns the referential action for UPDATE operations * on the referenced table the foreign key constraint is associated with. - * - * @return string|null */ - public function onUpdate() + public function onUpdate() : ?string { return $this->onEvent('onUpdate'); } @@ -339,10 +314,8 @@ public function onUpdate() /** * Returns the referential action for DELETE operations * on the referenced table the foreign key constraint is associated with. - * - * @return string|null */ - public function onDelete() + public function onDelete() : ?string { return $this->onEvent('onDelete'); } @@ -352,10 +325,8 @@ public function onDelete() * on the referenced table the foreign key constraint is associated with. * * @param string $event Name of the database operation/event to return the referential action for. - * - * @return string|null */ - private function onEvent($event) + private function onEvent(string $event) : ?string { if (isset($this->_options[$event])) { $onEvent = strtoupper($this->_options[$event]); @@ -365,7 +336,7 @@ private function onEvent($event) } } - return false; + return null; } /** @@ -375,10 +346,8 @@ private function onEvent($event) * matches one of the given index's columns, `false` otherwise. * * @param Index $index The index to be checked against. - * - * @return bool */ - public function intersectsIndexColumns(Index $index) + public function intersectsIndexColumns(Index $index) : bool { foreach ($index->getColumns() as $indexColumn) { foreach ($this->_localColumnNames as $localColumn) { diff --git a/lib/Doctrine/DBAL/Schema/Identifier.php b/lib/Doctrine/DBAL/Schema/Identifier.php index f34465e9efb..c3c84a7b62e 100644 --- a/lib/Doctrine/DBAL/Schema/Identifier.php +++ b/lib/Doctrine/DBAL/Schema/Identifier.php @@ -1,5 +1,7 @@ _setName($identifier); diff --git a/lib/Doctrine/DBAL/Schema/Index.php b/lib/Doctrine/DBAL/Schema/Index.php index 7a31c7824bf..b450c070315 100644 --- a/lib/Doctrine/DBAL/Schema/Index.php +++ b/lib/Doctrine/DBAL/Schema/Index.php @@ -1,25 +1,24 @@ Identifier) * - * @var Identifier[] + * @var array */ protected $_columns = []; @@ -31,9 +30,8 @@ class Index extends AbstractAsset implements Constraint /** * Platform specific flags for indexes. - * array($flagName => true) * - * @var true[] + * @var array */ protected $_flags = []; @@ -41,23 +39,23 @@ class Index extends AbstractAsset implements Constraint * Platform specific options * * @todo $_flags should eventually be refactored into options - * @var mixed[] + * @var array */ private $options = []; /** - * @param string $indexName - * @param string[] $columns - * @param bool $isUnique - * @param bool $isPrimary - * @param string[] $flags - * @param mixed[] $options + * @param array $columns + * @param array $flags + * @param array $options */ - public function __construct($indexName, array $columns, $isUnique = false, $isPrimary = false, array $flags = [], array $options = []) + public function __construct(?string $indexName, array $columns, bool $isUnique = false, bool $isPrimary = false, array $flags = [], array $options = []) { $isUnique = $isUnique || $isPrimary; - $this->_setName($indexName); + if ($indexName !== null) { + $this->_setName($indexName); + } + $this->_isUnique = $isUnique; $this->_isPrimary = $isPrimary; $this->options = $options; @@ -65,31 +63,21 @@ public function __construct($indexName, array $columns, $isUnique = false, $isPr foreach ($columns as $column) { $this->_addColumn($column); } + foreach ($flags as $flag) { $this->addFlag($flag); } } - /** - * @param string $column - * - * @return void - * - * @throws InvalidArgumentException - */ - protected function _addColumn($column) + protected function _addColumn(string $column) : void { - if (! is_string($column)) { - throw new InvalidArgumentException('Expecting a string as Index Column'); - } - $this->_columns[$column] = new Identifier($column); } /** * {@inheritdoc} */ - public function getColumns() + public function getColumns() : array { return array_keys($this->_columns); } @@ -97,7 +85,7 @@ public function getColumns() /** * {@inheritdoc} */ - public function getQuotedColumns(AbstractPlatform $platform) + public function getQuotedColumns(AbstractPlatform $platform) : array { $subParts = $platform->supportsColumnLengthIndexes() && $this->hasOption('lengths') ? $this->getOption('lengths') : []; @@ -120,46 +108,32 @@ public function getQuotedColumns(AbstractPlatform $platform) } /** - * @return string[] + * @return array */ - public function getUnquotedColumns() + public function getUnquotedColumns() : array { return array_map([$this, 'trimQuotes'], $this->getColumns()); } /** * Is the index neither unique nor primary key? - * - * @return bool */ - public function isSimpleIndex() + public function isSimpleIndex() : bool { return ! $this->_isPrimary && ! $this->_isUnique; } - /** - * @return bool - */ - public function isUnique() + public function isUnique() : bool { return $this->_isUnique; } - /** - * @return bool - */ - public function isPrimary() + public function isPrimary() : bool { return $this->_isPrimary; } - /** - * @param string $columnName - * @param int $pos - * - * @return bool - */ - public function hasColumnAtPosition($columnName, $pos = 0) + public function hasColumnAtPosition(string $columnName, int $pos = 0) : bool { $columnName = $this->trimQuotes(strtolower($columnName)); $indexColumns = array_map('strtolower', $this->getUnquotedColumns()); @@ -170,11 +144,9 @@ public function hasColumnAtPosition($columnName, $pos = 0) /** * Checks if this index exactly spans the given column names in the correct order. * - * @param string[] $columnNames - * - * @return bool + * @param array $columnNames */ - public function spansColumns(array $columnNames) + public function spansColumns(array $columnNames) : bool { $columns = $this->getColumns(); $numberOfColumns = count($columns); @@ -193,10 +165,8 @@ public function spansColumns(array $columnNames) /** * Checks if the other index already fulfills all the indexing and constraint needs of the current one. - * - * @return bool */ - public function isFullfilledBy(Index $other) + public function isFullfilledBy(Index $other) : bool { // allow the other index to be equally large only. It being larger is an option // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo) @@ -236,10 +206,8 @@ public function isFullfilledBy(Index $other) /** * Detects if the other index is a non-unique, non primary index that can be overwritten by this one. - * - * @return bool */ - public function overrules(Index $other) + public function overrules(Index $other) : bool { if ($other->isPrimary()) { return false; @@ -255,9 +223,9 @@ public function overrules(Index $other) /** * Returns platform specific flags for indexes. * - * @return string[] + * @return array */ - public function getFlags() + public function getFlags() : array { return array_keys($this->_flags); } @@ -265,13 +233,9 @@ public function getFlags() /** * Adds Flag for an index that translates to platform specific handling. * - * @param string $flag - * - * @return Index - * * @example $index->addFlag('CLUSTERED') */ - public function addFlag($flag) + public function addFlag(string $flag) : self { $this->_flags[strtolower($flag)] = true; @@ -280,62 +244,45 @@ public function addFlag($flag) /** * Does this index have a specific flag? - * - * @param string $flag - * - * @return bool */ - public function hasFlag($flag) + public function hasFlag(string $flag) : bool { return isset($this->_flags[strtolower($flag)]); } /** * Removes a flag. - * - * @param string $flag - * - * @return void */ - public function removeFlag($flag) + public function removeFlag(string $flag) : void { unset($this->_flags[strtolower($flag)]); } - /** - * @param string $name - * - * @return bool - */ - public function hasOption($name) + public function hasOption(string $name) : bool { return isset($this->options[strtolower($name)]); } /** - * @param string $name - * * @return mixed */ - public function getOption($name) + public function getOption(string $name) { return $this->options[strtolower($name)]; } /** - * @return mixed[] + * @return array */ - public function getOptions() + public function getOptions() : array { return $this->options; } /** * Return whether the two indexes have the same partial index - * - * @return bool */ - private function samePartialIndex(Index $other) + private function samePartialIndex(Index $other) : bool { if ($this->hasOption('where') && $other->hasOption('where') && $this->getOption('where') === $other->getOption('where')) { return true; diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index 5e0368509f7..6b47d2cc1e3 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -1,5 +1,7 @@ $user['User'], @@ -73,9 +75,9 @@ protected function _getPortableUserDefinition($user) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { - foreach ($tableIndexes as $k => $v) { + foreach ($tableIndexRows as $k => $v) { $v = array_change_key_case($v, CASE_LOWER); if ($v['key_name'] === 'PRIMARY') { $v['primary'] = true; @@ -89,16 +91,16 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null } $v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null; - $tableIndexes[$k] = $v; + $tableIndexRows[$k] = $v; } - return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + return parent::_getPortableTableIndexesList($tableIndexRows, $tableName); } /** * {@inheritdoc} */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { return $database['Database']; } @@ -106,7 +108,7 @@ protected function _getPortableDatabaseDefinition($database) /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); @@ -116,22 +118,17 @@ protected function _getPortableTableColumnDefinition($tableColumn) $length = $tableColumn['length'] ?? strtok('(), '); - $fixed = null; + $fixed = false; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } - $scale = null; + $scale = 0; $precision = null; - $type = $this->_platform->getDoctrineTypeMapping($dbType); - - // In cases where not connected to a database DESCRIBE $table does not return 'Comment' - if (isset($tableColumn['comment'])) { - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - } + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'char': @@ -144,8 +141,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) case 'numeric': case 'decimal': if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) { - $precision = $match[1]; - $scale = $match[2]; + $precision = (int) $match[1]; + $scale = (int) $match[2]; $length = null; } break; @@ -187,22 +184,17 @@ protected function _getPortableTableColumnDefinition($tableColumn) $options = [ 'length' => $length !== null ? (int) $length : null, 'unsigned' => strpos($tableColumn['type'], 'unsigned') !== false, - 'fixed' => (bool) $fixed, + 'fixed' => $fixed, 'default' => $columnDefault, 'notnull' => $tableColumn['null'] !== 'YES', - 'scale' => null, - 'precision' => null, + 'scale' => $scale, + 'precision' => $precision, 'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false, 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ]; - if ($scale !== null && $precision !== null) { - $options['scale'] = (int) $scale; - $options['precision'] = (int) $precision; - } - $column = new Column($tableColumn['field'], Type::getType($type), $options); if (isset($tableColumn['characterset'])) { @@ -256,7 +248,7 @@ private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?str /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $list = []; foreach ($tableForeignKeys as $value) { @@ -299,7 +291,10 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) return $result; } - public function listTableDetails($tableName) + /** + * {@inheritdoc} + */ + public function listTableDetails(string $tableName) : Table { $table = parent::listTableDetails($tableName); @@ -323,7 +318,7 @@ public function listTableDetails($tableName) } /** - * @return string[]|true[] + * @return array|array */ private function parseCreateOptions(?string $string) : array { diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index 0e9700a616d..7e6813a7b0d 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -1,5 +1,7 @@ getErrorCode() !== 1940) { + if ($exception->getCode() !== 1940) { throw $exception; } @@ -56,7 +58,7 @@ public function dropDatabase($database) /** * {@inheritdoc} */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { $view = array_change_key_case($view, CASE_LOWER); @@ -66,7 +68,7 @@ protected function _getPortableViewDefinition($view) /** * {@inheritdoc} */ - protected function _getPortableUserDefinition($user) + protected function _getPortableUserDefinition(array $user) : array { $user = array_change_key_case($user, CASE_LOWER); @@ -78,7 +80,7 @@ protected function _getPortableUserDefinition($user) /** * {@inheritdoc} */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { $table = array_change_key_case($table, CASE_LOWER); @@ -90,16 +92,16 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $indexBuffer = []; - foreach ($tableIndexes as $tableIndex) { + foreach ($tableIndexRows as $tableIndex) { $tableIndex = array_change_key_case($tableIndex, CASE_LOWER); $keyName = strtolower($tableIndex['name']); $buffer = []; - if (strtolower($tableIndex['is_primary']) === 'p') { + if ($tableIndex['is_primary'] === 'P') { $keyName = 'primary'; $buffer['primary'] = true; $buffer['non_unique'] = false; @@ -118,7 +120,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); @@ -131,14 +133,18 @@ protected function _getPortableTableColumnDefinition($tableColumn) } } - $unsigned = $fixed = $precision = $scale = $length = null; + $length = $precision = null; + $scale = 0; + $fixed = false; if (! isset($tableColumn['column_name'])) { $tableColumn['column_name'] = ''; } // Default values returned from database sometimes have trailing spaces. - $tableColumn['data_default'] = trim($tableColumn['data_default']); + if ($tableColumn['data_default'] !== null) { + $tableColumn['data_default'] = trim($tableColumn['data_default']); + } if ($tableColumn['data_default'] === '' || $tableColumn['data_default'] === 'NULL') { $tableColumn['data_default'] = null; @@ -159,9 +165,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $scale = (int) $tableColumn['data_scale']; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type); - $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comments']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'number': @@ -179,20 +184,18 @@ protected function _getPortableTableColumnDefinition($tableColumn) case 'varchar': case 'varchar2': case 'nvarchar2': - $length = $tableColumn['char_length']; - $fixed = false; + $length = (int) $tableColumn['char_length']; break; case 'char': case 'nchar': - $length = $tableColumn['char_length']; + $length = (int) $tableColumn['char_length']; $fixed = true; break; } $options = [ - 'notnull' => (bool) ($tableColumn['nullable'] === 'N'), - 'fixed' => (bool) $fixed, - 'unsigned' => (bool) $unsigned, + 'notnull' => $tableColumn['nullable'] === 'N', + 'fixed' => $fixed, 'default' => $tableColumn['data_default'], 'length' => $length, 'precision' => $precision, @@ -208,7 +211,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $list = []; foreach ($tableForeignKeys as $value) { @@ -251,7 +254,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableSequenceDefinition($sequence) + protected function _getPortableSequenceDefinition(array $sequence) : Sequence { $sequence = array_change_key_case($sequence, CASE_LOWER); @@ -265,17 +268,7 @@ protected function _getPortableSequenceDefinition($sequence) /** * {@inheritdoc} */ - protected function _getPortableFunctionDefinition($function) - { - $function = array_change_key_case($function, CASE_LOWER); - - return $function['name']; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { $database = array_change_key_case($database, CASE_LOWER); @@ -285,12 +278,8 @@ protected function _getPortableDatabaseDefinition($database) /** * {@inheritdoc} */ - public function createDatabase($database = null) + public function createDatabase(string $database) : void { - if ($database === null) { - $database = $this->_conn->getDatabase(); - } - $params = $this->_conn->getParams(); $username = $database; $password = $params['password']; @@ -302,12 +291,7 @@ public function createDatabase($database = null) $this->_conn->executeUpdate($query); } - /** - * @param string $table - * - * @return bool - */ - public function dropAutoincrement($table) + public function dropAutoincrement(string $table) : bool { assert($this->_platform instanceof OraclePlatform); @@ -322,7 +306,7 @@ public function dropAutoincrement($table) /** * {@inheritdoc} */ - public function dropTable($name) + public function dropTable(string $name) : void { $this->tryMethod('dropAutoincrement', $name); @@ -334,12 +318,8 @@ public function dropTable($name) * * Quotes non-uppercase identifiers explicitly to preserve case * and thus make references to the particular identifier work. - * - * @param string $identifier The identifier to quote. - * - * @return string The quoted identifier. */ - private function getQuotedIdentifierName($identifier) + private function getQuotedIdentifierName(string $identifier) : string { if (preg_match('/[a-z]/', $identifier)) { return $this->_platform->quoteIdentifier($identifier); @@ -354,10 +334,8 @@ private function getQuotedIdentifierName($identifier) * This is useful to force DROP USER operations which could fail because of active user sessions. * * @param string $user The name of the user to kill sessions for. - * - * @return void */ - private function killUserSessions($user) + private function killUserSessions(string $user) : void { $sql = << */ private $existingSchemaPaths; /** * Gets all the existing schema names. * - * @return string[] + * @return array */ - public function getSchemaNames() + public function getSchemaNames() : array { $statement = $this->_conn->executeQuery("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'"); @@ -51,9 +52,9 @@ public function getSchemaNames() * * This is a PostgreSQL only function. * - * @return string[] + * @return array */ - public function getSchemaSearchPaths() + public function getSchemaSearchPaths() : array { $params = $this->_conn->getParams(); $schema = explode(',', $this->_conn->fetchColumn('SHOW search_path')); @@ -70,9 +71,9 @@ public function getSchemaSearchPaths() * * This is a PostgreSQL only function. * - * @return string[] + * @return array */ - public function getExistingSchemaSearchPaths() + public function getExistingSchemaSearchPaths() : array { if ($this->existingSchemaPaths === null) { $this->determineExistingSchemaSearchPaths(); @@ -85,15 +86,13 @@ public function getExistingSchemaSearchPaths() * Sets or resets the order of the existing schemas in the current search path of the user. * * This is a PostgreSQL only function. - * - * @return void */ - public function determineExistingSchemaSearchPaths() + public function determineExistingSchemaSearchPaths() : void { $names = $this->getSchemaNames(); $paths = $this->getSchemaSearchPaths(); - $this->existingSchemaPaths = array_filter($paths, static function ($v) use ($names) { + $this->existingSchemaPaths = array_filter($paths, static function ($v) use ($names) : bool { return in_array($v, $names); }); } @@ -101,7 +100,7 @@ public function determineExistingSchemaSearchPaths() /** * {@inheritdoc} */ - public function dropDatabase($database) + public function dropDatabase(string $database) : void { try { parent::dropDatabase($database); @@ -130,7 +129,7 @@ public function dropDatabase($database) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint { $onUpdate = null; $onDelete = null; @@ -165,15 +164,7 @@ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) /** * {@inheritdoc} */ - protected function _getPortableTriggerDefinition($trigger) - { - return $trigger['trigger_name']; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']); } @@ -181,7 +172,7 @@ protected function _getPortableViewDefinition($view) /** * {@inheritdoc} */ - protected function _getPortableUserDefinition($user) + protected function _getPortableUserDefinition(array $user) : array { return [ 'user' => $user['usename'], @@ -192,7 +183,7 @@ protected function _getPortableUserDefinition($user) /** * {@inheritdoc} */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { $schemas = $this->getExistingSchemaSearchPaths(); $firstSchema = array_shift($schemas); @@ -209,10 +200,10 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $buffer = []; - foreach ($tableIndexes as $row) { + foreach ($tableIndexRows as $row) { $colNumbers = array_map('intval', explode(' ', $row['indkey'])); $columnNameSql = sprintf( 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', @@ -247,7 +238,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null /** * {@inheritdoc} */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { return $database['datname']; } @@ -255,7 +246,7 @@ protected function _getPortableDatabaseDefinition($database) /** * {@inheritdoc} */ - protected function _getPortableSequencesList($sequences) + protected function _getPortableSequencesList(array $sequences) : array { $sequenceDefinitions = []; @@ -281,7 +272,7 @@ protected function _getPortableSequencesList($sequences) /** * {@inheritdoc} */ - protected function getPortableNamespaceDefinition(array $namespace) + protected function getPortableNamespaceDefinition(array $namespace) : string { return $namespace['nspname']; } @@ -289,7 +280,7 @@ protected function getPortableNamespaceDefinition(array $namespace) /** * {@inheritdoc} */ - protected function _getPortableSequenceDefinition($sequence) + protected function _getPortableSequenceDefinition(array $sequence) : Sequence { if ($sequence['schemaname'] !== 'public') { $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; @@ -310,57 +301,63 @@ protected function _getPortableSequenceDefinition($sequence) /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); - if (strtolower($tableColumn['type']) === 'varchar' || strtolower($tableColumn['type']) === 'bpchar') { - // get length from varchar definition - $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']); - $tableColumn['length'] = $length; + $length = null; + + if (in_array(strtolower($tableColumn['type']), ['varchar', 'bpchar'], true) + && preg_match('/\((\d*)\)/', $tableColumn['complete_type'], $matches)) { + $length = (int) $matches[1]; } $matches = []; $autoincrement = false; - if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) { + if ($tableColumn['default'] !== null && preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) { $tableColumn['sequence'] = $matches[1]; $tableColumn['default'] = null; $autoincrement = true; } - if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches)) { - $tableColumn['default'] = $matches[1]; - } elseif (preg_match('/^NULL::/', $tableColumn['default'])) { - $tableColumn['default'] = null; + if ($tableColumn['default'] !== null) { + if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches)) { + $tableColumn['default'] = $matches[1]; + } elseif (preg_match('/^NULL::/', $tableColumn['default'])) { + $tableColumn['default'] = null; + } } - $length = $tableColumn['length'] ?? null; - if ($length === '-1' && isset($tableColumn['atttypmod'])) { + if ($length === -1 && isset($tableColumn['atttypmod'])) { $length = $tableColumn['atttypmod'] - 4; } + if ((int) $length <= 0) { $length = null; } - $fixed = null; + + $fixed = false; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } $precision = null; - $scale = null; + $scale = 0; $jsonb = null; $dbType = strtolower($tableColumn['type']); - if (strlen($tableColumn['domain_type']) && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) { + if ($tableColumn['domain_type'] !== null + && strlen($tableColumn['domain_type']) + && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type']) + ) { $dbType = strtolower($tableColumn['domain_type']); $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); switch ($dbType) { case 'smallint': @@ -395,10 +392,6 @@ protected function _getPortableTableColumnDefinition($tableColumn) case '_varchar': case 'varchar': $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']); - $fixed = false; - break; - case 'interval': - $fixed = false; break; case 'char': case 'bpchar': @@ -416,8 +409,8 @@ protected function _getPortableTableColumnDefinition($tableColumn) $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) { - $precision = $match[1]; - $scale = $match[2]; + $precision = (int) $match[1]; + $scale = (int) $match[2]; $length = null; } break; @@ -455,7 +448,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) $column->setPlatformOption('collation', $tableColumn['collation']); } - if (in_array($column->getType()->getName(), [Types::JSON_ARRAY, Types::JSON], true)) { + if ($column->getType()->getName() === Types::JSON) { $column->setPlatformOption('jsonb', $jsonb); } @@ -471,7 +464,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) */ private function fixVersion94NegativeNumericDefaultValue($defaultValue) { - if (strpos($defaultValue, '(') === 0) { + if ($defaultValue !== null && strpos($defaultValue, '(') === 0) { return trim($defaultValue, '()'); } diff --git a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php index c169a6e0708..58ae1f4d906 100644 --- a/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php @@ -1,5 +1,7 @@ startDatabase($database); @@ -37,29 +39,19 @@ public function createDatabase($database) * * @see stopDatabase */ - public function dropDatabase($database) + public function dropDatabase(string $database) : void { $this->tryMethod('stopDatabase', $database); parent::dropDatabase($database); } - /** - * Starts a database. - * - * @param string $database The name of the database to start. - */ - public function startDatabase($database) + public function startDatabase(string $database) : void { assert($this->_platform instanceof SQLAnywherePlatform); $this->_execSql($this->_platform->getStartDatabaseSQL($database)); } - /** - * Stops a database. - * - * @param string $database The name of the database to stop. - */ - public function stopDatabase($database) + public function stopDatabase(string $database) : void { assert($this->_platform instanceof SQLAnywherePlatform); $this->_execSql($this->_platform->getStopDatabaseSQL($database)); @@ -68,7 +60,7 @@ public function stopDatabase($database) /** * {@inheritdoc} */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { return $database['name']; } @@ -76,7 +68,7 @@ protected function _getPortableDatabaseDefinition($database) /** * {@inheritdoc} */ - protected function _getPortableSequenceDefinition($sequence) + protected function _getPortableSequenceDefinition(array $sequence) : Sequence { return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['start_with']); } @@ -84,15 +76,15 @@ protected function _getPortableSequenceDefinition($sequence) /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { - $type = $this->_platform->getDoctrineTypeMapping($tableColumn['type']); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); - $precision = null; - $scale = null; - $fixed = false; - $default = null; + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($tableColumn['type']); + + $precision = null; + $scale = null; + $fixed = false; + $default = null; if ($tableColumn['default'] !== null) { // Strip quotes from default value. @@ -139,7 +131,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) /** * {@inheritdoc} */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { return $table['table_name']; } @@ -147,7 +139,7 @@ protected function _getPortableTableDefinition($table) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], @@ -161,7 +153,7 @@ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $foreignKeys = []; @@ -194,7 +186,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['primary'] = (bool) $tableIndex['primary']; @@ -221,7 +213,7 @@ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = nu /** * {@inheritdoc} */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { $definition = preg_replace('/^.*\s+as\s+SELECT(.*)/i', 'SELECT$1', $view['view_def']); assert(is_string($definition)); diff --git a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php index 31ec6fffd50..80d7eae06b6 100644 --- a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -1,5 +1,7 @@ getErrorCode() !== 3702) { + if ($exception->getCode() !== 3702) { throw $exception; } @@ -54,7 +56,7 @@ public function dropDatabase($database) /** * {@inheritdoc} */ - protected function _getPortableSequenceDefinition($sequence) + protected function _getPortableSequenceDefinition(array $sequence) : Sequence { return new Sequence($sequence['name'], (int) $sequence['increment'], (int) $sequence['start_value']); } @@ -62,21 +64,32 @@ protected function _getPortableSequenceDefinition($sequence) /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { $dbType = strtok($tableColumn['type'], '(), '); assert(is_string($dbType)); - $fixed = null; - $length = (int) $tableColumn['length']; - $default = $tableColumn['default']; + $length = (int) $tableColumn['length']; + + $precision = $default = null; + + $scale = 0; + $fixed = false; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } - if ($default !== null) { - $default = $this->parseDefaultExpression($default); + if ($tableColumn['scale'] !== null) { + $scale = (int) $tableColumn['scale']; + } + + if ($tableColumn['precision'] !== null) { + $precision = (int) $tableColumn['precision']; + } + + if ($tableColumn['default'] !== null) { + $default = $this->parseDefaultExpression($tableColumn['default']); } switch ($dbType) { @@ -98,18 +111,16 @@ protected function _getPortableTableColumnDefinition($tableColumn) $fixed = true; } - $type = $this->_platform->getDoctrineTypeMapping($dbType); - $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); - $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) + ?? $this->_platform->getDoctrineTypeMapping($dbType); $options = [ 'length' => $length === 0 || ! in_array($type, ['text', 'string']) ? null : $length, - 'unsigned' => false, - 'fixed' => (bool) $fixed, + 'fixed' => $fixed, 'default' => $default, 'notnull' => (bool) $tableColumn['notnull'], - 'scale' => $tableColumn['scale'], - 'precision' => $tableColumn['precision'], + 'scale' => $scale, + 'precision' => $precision, 'autoincrement' => (bool) $tableColumn['autoincrement'], 'comment' => $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ]; @@ -147,7 +158,7 @@ private function parseDefaultExpression(string $value) : ?string /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $foreignKeys = []; @@ -175,7 +186,7 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) /** * {@inheritdoc} */ - protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['non_unique'] = (bool) $tableIndex['non_unique']; @@ -189,7 +200,7 @@ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = nu /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], @@ -203,7 +214,7 @@ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) /** * {@inheritdoc} */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { if (isset($table['schema_name']) && $table['schema_name'] !== 'dbo') { return $table['schema_name'] . '.' . $table['name']; @@ -215,7 +226,7 @@ protected function _getPortableTableDefinition($table) /** * {@inheritdoc} */ - protected function _getPortableDatabaseDefinition($database) + protected function _getPortableDatabaseDefinition(array $database) : string { return $database['name']; } @@ -223,7 +234,7 @@ protected function _getPortableDatabaseDefinition($database) /** * {@inheritdoc} */ - protected function getPortableNamespaceDefinition(array $namespace) + protected function getPortableNamespaceDefinition(array $namespace) : string { return $namespace['name']; } @@ -231,7 +242,7 @@ protected function getPortableNamespaceDefinition(array $namespace) /** * {@inheritdoc} */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { // @todo return new View($view['name'], ''); @@ -240,7 +251,7 @@ protected function _getPortableViewDefinition($view) /** * {@inheritdoc} */ - public function listTableIndexes($table) + public function listTableIndexes(string $table) : array { $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); @@ -266,7 +277,7 @@ public function listTableIndexes($table) /** * {@inheritdoc} */ - public function alterTable(TableDiff $tableDiff) + public function alterTable(TableDiff $tableDiff) : void { if (count($tableDiff->removedColumns) > 0) { foreach ($tableDiff->removedColumns as $col) { @@ -288,13 +299,8 @@ public function alterTable(TableDiff $tableDiff) /** * Returns the SQL to retrieve the constraints for a given column. - * - * @param string $table - * @param string $column - * - * @return string */ - private function getColumnConstraintSQL($table, $column) + private function getColumnConstraintSQL(string $table, string $column) : string { return "SELECT SysObjects.[Name] FROM SysObjects INNER JOIN (SELECT [Name],[ID] FROM SysObjects WHERE XType = 'U') AS Tab @@ -309,12 +315,8 @@ private function getColumnConstraintSQL($table, $column) * Closes currently active connections on the given database. * * This is useful to force DROP DATABASE operations which could fail because of active connections. - * - * @param string $database The name of the database to close currently active connections for. - * - * @return void */ - private function closeActiveDatabaseConnections($database) + private function closeActiveDatabaseConnections(string $database) : void { $database = new Identifier($database); diff --git a/lib/Doctrine/DBAL/Schema/Schema.php b/lib/Doctrine/DBAL/Schema/Schema.php index 5d746654a40..96e2f111c76 100644 --- a/lib/Doctrine/DBAL/Schema/Schema.php +++ b/lib/Doctrine/DBAL/Schema/Schema.php @@ -1,8 +1,15 @@ */ private $namespaces = []; - /** @var Table[] */ + /** @var array */ protected $_tables = []; - /** @var Sequence[] */ + /** @var array */ protected $_sequences = []; /** @var SchemaConfig */ - protected $_schemaConfig = false; + protected $_schemaConfig; /** - * @param Table[] $tables - * @param Sequence[] $sequences - * @param string[] $namespaces + * @param array $tables + * @param array $sequences + * @param array $namespaces */ public function __construct( array $tables = [], @@ -83,26 +90,21 @@ public function __construct( } } - /** - * @return bool - */ - public function hasExplicitForeignKeyIndexes() + public function hasExplicitForeignKeyIndexes() : bool { return $this->_schemaConfig->hasExplicitForeignKeyIndexes(); } /** - * @return void - * * @throws SchemaException */ - protected function _addTable(Table $table) + protected function _addTable(Table $table) : void { $namespaceName = $table->getNamespaceName(); $tableName = $table->getFullQualifiedName($this->getName()); if (isset($this->_tables[$tableName])) { - throw SchemaException::tableAlreadyExists($tableName); + throw TableAlreadyExists::new($tableName); } if ($namespaceName !== null @@ -116,17 +118,15 @@ protected function _addTable(Table $table) } /** - * @return void - * * @throws SchemaException */ - protected function _addSequence(Sequence $sequence) + protected function _addSequence(Sequence $sequence) : void { $namespaceName = $sequence->getNamespaceName(); $seqName = $sequence->getFullQualifiedName($this->getName()); if (isset($this->_sequences[$seqName])) { - throw SchemaException::sequenceAlreadyExists($seqName); + throw SequenceAlreadyExists::new($seqName); } if ($namespaceName !== null @@ -141,9 +141,9 @@ protected function _addSequence(Sequence $sequence) /** * Returns the namespaces of this schema. * - * @return string[] A list of namespace names. + * @return array A list of namespace names. */ - public function getNamespaces() + public function getNamespaces() : array { return $this->namespaces; } @@ -151,36 +151,27 @@ public function getNamespaces() /** * Gets all tables of this schema. * - * @return Table[] + * @return array */ - public function getTables() + public function getTables() : array { return $this->_tables; } /** - * @param string $tableName - * - * @return Table - * * @throws SchemaException */ - public function getTable($tableName) + public function getTable(string $tableName) : Table { $tableName = $this->getFullQualifiedAssetName($tableName); if (! isset($this->_tables[$tableName])) { - throw SchemaException::tableDoesNotExist($tableName); + throw TableDoesNotExist::new($tableName); } return $this->_tables[$tableName]; } - /** - * @param string $name - * - * @return string - */ - private function getFullQualifiedAssetName($name) + private function getFullQualifiedAssetName(string $name) : string { $name = $this->getUnquotedAssetName($name); @@ -193,12 +184,8 @@ private function getFullQualifiedAssetName($name) /** * Returns the unquoted representation of a given asset name. - * - * @param string $assetName Quoted or unquoted representation of an asset name. - * - * @return string */ - private function getUnquotedAssetName($assetName) + private function getUnquotedAssetName(string $assetName) : string { if ($this->isIdentifierQuoted($assetName)) { return $this->trimQuotes($assetName); @@ -209,12 +196,8 @@ private function getUnquotedAssetName($assetName) /** * Does this schema have a namespace with the given name? - * - * @param string $namespaceName - * - * @return bool */ - public function hasNamespace($namespaceName) + public function hasNamespace(string $namespaceName) : bool { $namespaceName = strtolower($this->getUnquotedAssetName($namespaceName)); @@ -223,12 +206,8 @@ public function hasNamespace($namespaceName) /** * Does this schema have a table with the given name? - * - * @param string $tableName - * - * @return bool */ - public function hasTable($tableName) + public function hasTable(string $tableName) : bool { $tableName = $this->getFullQualifiedAssetName($tableName); @@ -238,19 +217,14 @@ public function hasTable($tableName) /** * Gets all table names, prefixed with a schema name, even the default one if present. * - * @return string[] + * @return array */ - public function getTableNames() + public function getTableNames() : array { return array_keys($this->_tables); } - /** - * @param string $sequenceName - * - * @return bool - */ - public function hasSequence($sequenceName) + public function hasSequence(string $sequenceName) : bool { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); @@ -258,26 +232,22 @@ public function hasSequence($sequenceName) } /** - * @param string $sequenceName - * - * @return Sequence - * * @throws SchemaException */ - public function getSequence($sequenceName) + public function getSequence(string $sequenceName) : Sequence { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); if (! $this->hasSequence($sequenceName)) { - throw SchemaException::sequenceDoesNotExist($sequenceName); + throw SequenceDoesNotExist::new($sequenceName); } return $this->_sequences[$sequenceName]; } /** - * @return Sequence[] + * @return array */ - public function getSequences() + public function getSequences() : array { return $this->_sequences; } @@ -285,18 +255,16 @@ public function getSequences() /** * Creates a new namespace. * - * @param string $namespaceName The name of the namespace to create. - * - * @return \Doctrine\DBAL\Schema\Schema This schema instance. + * @return $this * * @throws SchemaException */ - public function createNamespace($namespaceName) + public function createNamespace(string $namespaceName) : self { $unquotedNamespaceName = strtolower($this->getUnquotedAssetName($namespaceName)); if (isset($this->namespaces[$unquotedNamespaceName])) { - throw SchemaException::namespaceAlreadyExists($unquotedNamespaceName); + throw NamespaceAlreadyExists::new($unquotedNamespaceName); } $this->namespaces[$unquotedNamespaceName] = $namespaceName; @@ -306,12 +274,8 @@ public function createNamespace($namespaceName) /** * Creates a new table. - * - * @param string $tableName - * - * @return Table */ - public function createTable($tableName) + public function createTable(string $tableName) : Table { $table = new Table($tableName); $this->_addTable($table); @@ -326,12 +290,9 @@ public function createTable($tableName) /** * Renames a table. * - * @param string $oldTableName - * @param string $newTableName - * - * @return \Doctrine\DBAL\Schema\Schema + * @return $this */ - public function renameTable($oldTableName, $newTableName) + public function renameTable(string $oldTableName, string $newTableName) : self { $table = $this->getTable($oldTableName); $table->_setName($newTableName); @@ -345,11 +306,9 @@ public function renameTable($oldTableName, $newTableName) /** * Drops a table from the schema. * - * @param string $tableName - * - * @return \Doctrine\DBAL\Schema\Schema + * @return $this */ - public function dropTable($tableName) + public function dropTable(string $tableName) : self { $tableName = $this->getFullQualifiedAssetName($tableName); $this->getTable($tableName); @@ -360,14 +319,8 @@ public function dropTable($tableName) /** * Creates a new sequence. - * - * @param string $sequenceName - * @param int $allocationSize - * @param int $initialValue - * - * @return Sequence */ - public function createSequence($sequenceName, $allocationSize = 1, $initialValue = 1) + public function createSequence(string $sequenceName, int $allocationSize = 1, int $initialValue = 1) : Sequence { $seq = new Sequence($sequenceName, $allocationSize, $initialValue); $this->_addSequence($seq); @@ -376,11 +329,9 @@ public function createSequence($sequenceName, $allocationSize = 1, $initialValue } /** - * @param string $sequenceName - * - * @return \Doctrine\DBAL\Schema\Schema + * @return $this */ - public function dropSequence($sequenceName) + public function dropSequence(string $sequenceName) : self { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); unset($this->_sequences[$sequenceName]); @@ -391,9 +342,9 @@ public function dropSequence($sequenceName) /** * Returns an array of necessary SQL queries to create the schema on the given platform. * - * @return string[] + * @return array */ - public function toSql(AbstractPlatform $platform) + public function toSql(AbstractPlatform $platform) : array { $sqlCollector = new CreateSchemaSqlCollector($platform); $this->visit($sqlCollector); @@ -404,9 +355,9 @@ public function toSql(AbstractPlatform $platform) /** * Return an array of necessary SQL queries to drop the schema on the given platform. * - * @return string[] + * @return array */ - public function toDropSql(AbstractPlatform $platform) + public function toDropSql(AbstractPlatform $platform) : array { $dropSqlCollector = new DropSchemaSqlCollector($platform); $this->visit($dropSqlCollector); @@ -415,9 +366,9 @@ public function toDropSql(AbstractPlatform $platform) } /** - * @return string[] + * @return array */ - public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform) + public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform) : array { $comparator = new Comparator(); $schemaDiff = $comparator->compare($this, $toSchema); @@ -426,9 +377,9 @@ public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform) } /** - * @return string[] + * @return array */ - public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform) + public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform) : array { $comparator = new Comparator(); $schemaDiff = $comparator->compare($fromSchema, $this); @@ -436,10 +387,7 @@ public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform return $schemaDiff->toSql($platform); } - /** - * @return void - */ - public function visit(Visitor $visitor) + public function visit(Visitor $visitor) : void { $visitor->acceptSchema($this); @@ -460,8 +408,6 @@ public function visit(Visitor $visitor) /** * Cloning a Schema triggers a deep clone of all related assets. - * - * @return void */ public function __clone() { diff --git a/lib/Doctrine/DBAL/Schema/SchemaConfig.php b/lib/Doctrine/DBAL/Schema/SchemaConfig.php index b8c3502f758..ef2dc0b91a5 100644 --- a/lib/Doctrine/DBAL/Schema/SchemaConfig.php +++ b/lib/Doctrine/DBAL/Schema/SchemaConfig.php @@ -1,5 +1,7 @@ */ protected $defaultTableOptions = []; - /** - * @return bool - */ - public function hasExplicitForeignKeyIndexes() + public function hasExplicitForeignKeyIndexes() : bool { return $this->hasExplicitForeignKeyIndexes; } - /** - * @param bool $flag - * - * @return void - */ - public function setExplicitForeignKeyIndexes($flag) + public function setExplicitForeignKeyIndexes(bool $flag) : void { - $this->hasExplicitForeignKeyIndexes = (bool) $flag; + $this->hasExplicitForeignKeyIndexes = $flag; } - /** - * @param int $length - * - * @return void - */ - public function setMaxIdentifierLength($length) + public function setMaxIdentifierLength(int $length) : void { - $this->maxIdentifierLength = (int) $length; + $this->maxIdentifierLength = $length; } - /** - * @return int - */ - public function getMaxIdentifierLength() + public function getMaxIdentifierLength() : int { return $this->maxIdentifierLength; } /** * Gets the default namespace of schema objects. - * - * @return string */ - public function getName() + public function getName() : ?string { return $this->name; } /** * Sets the default namespace name of schema objects. - * - * @param string $name The value to set. - * - * @return void */ - public function setName($name) + public function setName(string $name) : void { $this->name = $name; } @@ -81,19 +61,17 @@ public function setName($name) * Gets the default options that are passed to Table instances created with * Schema#createTable(). * - * @return mixed[] + * @return array */ - public function getDefaultTableOptions() + public function getDefaultTableOptions() : array { return $this->defaultTableOptions; } /** - * @param mixed[] $defaultTableOptions - * - * @return void + * @param array $defaultTableOptions */ - public function setDefaultTableOptions(array $defaultTableOptions) + public function setDefaultTableOptions(array $defaultTableOptions) : void { $this->defaultTableOptions = $defaultTableOptions; } diff --git a/lib/Doctrine/DBAL/Schema/SchemaDiff.php b/lib/Doctrine/DBAL/Schema/SchemaDiff.php index 69bf125a844..92281181cb6 100644 --- a/lib/Doctrine/DBAL/Schema/SchemaDiff.php +++ b/lib/Doctrine/DBAL/Schema/SchemaDiff.php @@ -1,5 +1,7 @@ */ public $newNamespaces = []; /** * All removed namespaces. * - * @var string[] + * @var array */ public $removedNamespaces = []; /** * All added tables. * - * @var Table[] + * @var array */ public $newTables = []; /** * All changed tables. * - * @var TableDiff[] + * @var array */ public $changedTables = []; /** * All removed tables. * - * @var Table[] + * @var array */ public $removedTables = []; - /** @var Sequence[] */ + /** @var array */ public $newSequences = []; - /** @var Sequence[] */ + /** @var array */ public $changedSequences = []; - /** @var Sequence[] */ + /** @var array */ public $removedSequences = []; - /** @var ForeignKeyConstraint[] */ + /** @var array */ public $orphanedForeignKeys = []; /** * Constructs an SchemaDiff object. * - * @param Table[] $newTables - * @param TableDiff[] $changedTables - * @param Table[] $removedTables + * @param array $newTables + * @param array $changedTables + * @param array $removedTables */ - public function __construct($newTables = [], $changedTables = [], $removedTables = [], ?Schema $fromSchema = null) + public function __construct(array $newTables = [], array $changedTables = [], array $removedTables = [], ?Schema $fromSchema = null) { $this->newTables = $newTables; $this->changedTables = $changedTables; @@ -84,27 +86,25 @@ public function __construct($newTables = [], $changedTables = [], $removedTables * * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all. * - * @return string[] + * @return array */ - public function toSaveSql(AbstractPlatform $platform) + public function toSaveSql(AbstractPlatform $platform) : array { return $this->_toSql($platform, true); } /** - * @return string[] + * @return array */ - public function toSql(AbstractPlatform $platform) + public function toSql(AbstractPlatform $platform) : array { return $this->_toSql($platform, false); } /** - * @param bool $saveMode - * - * @return string[] + * @return array */ - protected function _toSql(AbstractPlatform $platform, $saveMode = false) + protected function _toSql(AbstractPlatform $platform, bool $saveMode = false) : array { $sql = []; @@ -120,7 +120,7 @@ protected function _toSql(AbstractPlatform $platform, $saveMode = false) } } - if ($platform->supportsSequences() === true) { + if ($platform->supportsSequences()) { foreach ($this->changedSequences as $sequence) { $sql[] = $platform->getAlterSequenceSQL($sequence); } diff --git a/lib/Doctrine/DBAL/Schema/SchemaException.php b/lib/Doctrine/DBAL/Schema/SchemaException.php index 213d218475b..84101b2f071 100644 --- a/lib/Doctrine/DBAL/Schema/SchemaException.php +++ b/lib/Doctrine/DBAL/Schema/SchemaException.php @@ -1,10 +1,10 @@ getName() . ' requires a named foreign key, ' . - 'but the given foreign key from (' . implode(', ', $foreignKey->getColumns()) . ') onto foreign table ' . - "'" . $foreignKey->getForeignTableName() . "' (" . implode(', ', $foreignKey->getForeignColumns()) . ') is currently ' . - 'unnamed.' - ); - } - - /** - * @param string $changeName - * - * @return \Doctrine\DBAL\Schema\SchemaException - */ - public static function alterTableChangeNotSupported($changeName) - { - return new self( - sprintf("Alter table change not supported, given '%s'", $changeName) - ); - } + public const CONSTRAINT_DOESNT_EXIST = 110; + public const NAMESPACE_ALREADY_EXISTS = 120; } diff --git a/lib/Doctrine/DBAL/Schema/Sequence.php b/lib/Doctrine/DBAL/Schema/Sequence.php index 88891019bfd..86989250d2d 100644 --- a/lib/Doctrine/DBAL/Schema/Sequence.php +++ b/lib/Doctrine/DBAL/Schema/Sequence.php @@ -1,5 +1,7 @@ _setName($name); $this->setAllocationSize($allocationSize); @@ -34,60 +30,36 @@ public function __construct($name, $allocationSize = 1, $initialValue = 1, $cach $this->cache = $cache; } - /** - * @return int - */ - public function getAllocationSize() + public function getAllocationSize() : int { return $this->allocationSize; } - /** - * @return int - */ - public function getInitialValue() + public function getInitialValue() : int { return $this->initialValue; } - /** - * @return int|null - */ - public function getCache() + public function getCache() : ?int { return $this->cache; } - /** - * @param int $allocationSize - * - * @return \Doctrine\DBAL\Schema\Sequence - */ - public function setAllocationSize($allocationSize) + public function setAllocationSize(int $allocationSize) : self { - $this->allocationSize = (int) $allocationSize ?: 1; + $this->allocationSize = $allocationSize; return $this; } - /** - * @param int $initialValue - * - * @return \Doctrine\DBAL\Schema\Sequence - */ - public function setInitialValue($initialValue) + public function setInitialValue(int $initialValue) : self { - $this->initialValue = (int) $initialValue ?: 1; + $this->initialValue = $initialValue; return $this; } - /** - * @param int $cache - * - * @return \Doctrine\DBAL\Schema\Sequence - */ - public function setCache($cache) + public function setCache(int $cache) : self { $this->cache = $cache; @@ -99,10 +71,8 @@ public function setCache($cache) * * This is used inside the comparator to not report sequences as missing, * when the "from" schema implicitly creates the sequences. - * - * @return bool */ - public function isAutoIncrementsFor(Table $table) + public function isAutoIncrementsFor(Table $table) : bool { $primaryKey = $table->getPrimaryKey(); @@ -129,10 +99,7 @@ public function isAutoIncrementsFor(Table $table) return $tableSequenceName === $sequenceName; } - /** - * @return void - */ - public function visit(Visitor $visitor) + public function visit(Visitor $visitor) : void { $visitor->acceptSequence($this); } diff --git a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php index 66d3c8503d5..fb2e1673565 100644 --- a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -1,8 +1,9 @@ _conn->getParams(); $driver = $params['driver']; @@ -64,7 +65,7 @@ public function createDatabase($database) /** * {@inheritdoc} */ - public function renameTable($name, $newName) + public function renameTable(string $name, string $newName) : void { $tableDiff = new TableDiff($name); $tableDiff->fromTable = $this->listTableDetails($name); @@ -75,9 +76,12 @@ public function renameTable($name, $newName) /** * {@inheritdoc} */ - public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) + public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void { - $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $table = $this->ensureTable($table); + + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $tableDiff->addedForeignKeys[] = $foreignKey; $this->alterTable($tableDiff); @@ -86,9 +90,12 @@ public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) /** * {@inheritdoc} */ - public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) : void { - $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $table = $this->ensureTable($table); + + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + $tableDiff->changedForeignKeys[] = $foreignKey; $this->alterTable($tableDiff); @@ -97,10 +104,17 @@ public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table /** * {@inheritdoc} */ - public function dropForeignKey($foreignKey, $table) + public function dropForeignKey($foreignKey, $table) : void { - $tableDiff = $this->getTableDiffForAlterForeignKey($table); - $tableDiff->removedForeignKeys[] = $foreignKey; + $table = $this->ensureTable($table); + + $tableDiff = $this->getTableDiffForAlterForeignKey($table); + + if (is_string($foreignKey)) { + $tableDiff->removedForeignKeys[] = $table->getForeignKey($foreignKey); + } else { + $tableDiff->removedForeignKeys[] = $foreignKey; + } $this->alterTable($tableDiff); } @@ -108,7 +122,7 @@ public function dropForeignKey($foreignKey, $table) /** * {@inheritdoc} */ - public function listTableForeignKeys($table, $database = null) + public function listTableForeignKeys(string $table, ?string $database = null) : array { if ($database === null) { $database = $this->_conn->getDatabase(); @@ -153,7 +167,7 @@ public function listTableForeignKeys($table, $database = null) /** * {@inheritdoc} */ - protected function _getPortableTableDefinition($table) + protected function _getPortableTableDefinition(array $table) : string { return $table['name']; } @@ -163,7 +177,7 @@ protected function _getPortableTableDefinition($table) * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ - protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array { $indexBuffer = []; @@ -195,7 +209,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null } // fetch regular indexes - foreach ($tableIndexes as $tableIndex) { + foreach ($tableIndexRows as $tableIndex) { // Ignore indexes with reserved names, e.g. autoindexes if (strpos($tableIndex['name'], 'sqlite_') === 0) { continue; @@ -225,18 +239,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null /** * {@inheritdoc} */ - protected function _getPortableTableIndexDefinition($tableIndex) - { - return [ - 'name' => $tableIndex['name'], - 'unique' => (bool) $tableIndex['unique'], - ]; - } - - /** - * {@inheritdoc} - */ - protected function _getPortableTableColumnList($table, $database, $tableColumns) + protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns) : array { $list = parent::_getPortableTableColumnList($table, $database, $tableColumns); @@ -279,16 +282,10 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns) $comment = $this->parseColumnCommentFromSQL($columnName, $createSql); - if ($comment === null) { - continue; - } - - $type = $this->extractDoctrineTypeFromComment($comment, ''); + $type = $this->extractDoctrineTypeFromComment($comment); - if ($type !== '') { + if ($type !== null) { $column->setType(Type::getType($type)); - - $comment = $this->removeDoctrineTypeFromComment($comment, $type); } $column->setComment($comment); @@ -300,25 +297,28 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns) /** * {@inheritdoc} */ - protected function _getPortableTableColumnDefinition($tableColumn) + protected function _getPortableTableColumnDefinition(array $tableColumn) : Column { - $parts = explode('(', $tableColumn['type']); - $tableColumn['type'] = trim($parts[0]); - if (isset($parts[1])) { - $length = trim($parts[1], ')'); - $tableColumn['length'] = $length; - } + preg_match('/^([^()]*)\\s*(\\(((\\d+)(,\\s*(\\d+))?)\\))?/', $tableColumn['type'], $matches); - $dbType = strtolower($tableColumn['type']); - $length = $tableColumn['length'] ?? null; - $unsigned = false; + $dbType = trim(strtolower($matches[1])); + + $length = $precision = $unsigned = null; + $fixed = $unsigned = false; + $scale = 0; + + if (count($matches) >= 6) { + $precision = (int) $matches[4]; + $scale = (int) $matches[6]; + } elseif (count($matches) >= 4) { + $length = (int) $matches[4]; + } if (strpos($dbType, ' unsigned') !== false) { $dbType = str_replace(' unsigned', '', $dbType); $unsigned = true; } - $fixed = false; $type = $this->_platform->getDoctrineTypeMapping($dbType); $default = $tableColumn['dflt_value']; if ($default === 'NULL') { @@ -338,31 +338,13 @@ protected function _getPortableTableColumnDefinition($tableColumn) $tableColumn['name'] = ''; } - $precision = null; - $scale = null; - - switch ($dbType) { - case 'char': - $fixed = true; - break; - case 'float': - case 'double': - case 'real': - case 'decimal': - case 'numeric': - if (isset($tableColumn['length'])) { - if (strpos($tableColumn['length'], ',') === false) { - $tableColumn['length'] .= ',0'; - } - [$precision, $scale] = array_map('trim', explode(',', $tableColumn['length'])); - } - $length = null; - break; + if ($dbType === 'char') { + $fixed = true; } $options = [ 'length' => $length, - 'unsigned' => (bool) $unsigned, + 'unsigned' => $unsigned, 'fixed' => $fixed, 'notnull' => $notnull, 'default' => $default, @@ -377,7 +359,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) /** * {@inheritdoc} */ - protected function _getPortableViewDefinition($view) + protected function _getPortableViewDefinition(array $view) : View { return new View($view['name'], $view['sql']); } @@ -385,7 +367,7 @@ protected function _getPortableViewDefinition($view) /** * {@inheritdoc} */ - protected function _getPortableTableForeignKeysList($tableForeignKeys) + protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array { $list = []; foreach ($tableForeignKeys as $value) { @@ -433,31 +415,26 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) return $result; } - /** - * @param Table|string $table - * - * @return TableDiff - * - * @throws DBALException - */ - private function getTableDiffForAlterForeignKey($table) + private function getTableDiffForAlterForeignKey(Table $table) : TableDiff { - if (! $table instanceof Table) { - $tableDetails = $this->tryMethod('listTableDetails', $table); - - if ($tableDetails === false) { - throw new DBALException(sprintf('Sqlite schema manager requires to modify foreign keys table definition "%s".', $table)); - } - - $table = $tableDetails; - } - $tableDiff = new TableDiff($table->getName()); $tableDiff->fromTable = $table; return $tableDiff; } + /** + * @param string|Table $table + */ + private function ensureTable($table) : Table + { + if (is_string($table)) { + $table = $this->listTableDetails($table); + } + + return $table; + } + private function parseColumnCollationFromSQL(string $column, string $sql) : ?string { $pattern = '{(?:\W' . preg_quote($column) . '\W|\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) diff --git a/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php b/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php index b597b8db9b2..3ec2ebd649f 100644 --- a/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php +++ b/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php @@ -1,5 +1,7 @@ $sql */ - protected function processSqlSafely(array $sql) + protected function processSqlSafely(array $sql) : void { foreach ($sql as $s) { try { @@ -32,9 +34,9 @@ protected function processSqlSafely(array $sql) } /** - * @param string[] $sql + * @param array $sql */ - protected function processSql(array $sql) + protected function processSql(array $sql) : void { foreach ($sql as $s) { $this->conn->exec($s); diff --git a/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php b/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php index 3e7beea7508..58ab02e67d5 100644 --- a/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php +++ b/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php @@ -1,5 +1,7 @@ */ - public function getCreateSchema(Schema $createSchema); + public function getCreateSchema(Schema $createSchema) : array; /** * Gets the SQL Statements to update given schema with the underlying db. * - * @param bool $noDrops - * - * @return string[] + * @return array */ - public function getUpdateSchema(Schema $toSchema, $noDrops = false); + public function getUpdateSchema(Schema $toSchema, bool $noDrops = false) : array; /** * Gets the SQL Statements to drop the given schema from underlying db. * * @return string[] */ - public function getDropSchema(Schema $dropSchema); + public function getDropSchema(Schema $dropSchema) : array; /** * Gets the SQL statements to drop all schema assets from underlying db. * - * @return string[] + * @return array */ - public function getDropAllSchema(); + public function getDropAllSchema() : array; /** * Creates the Schema. - * - * @return void */ - public function createSchema(Schema $createSchema); + public function createSchema(Schema $createSchema) : void; /** * Updates the Schema to new schema version. - * - * @param bool $noDrops - * - * @return void */ - public function updateSchema(Schema $toSchema, $noDrops = false); + public function updateSchema(Schema $toSchema, bool $noDrops = false) : void; /** * Drops the given database schema from the underlying db. - * - * @return void */ - public function dropSchema(Schema $dropSchema); + public function dropSchema(Schema $dropSchema) : void; /** * Drops all assets from the underlying db. - * - * @return void */ - public function dropAllSchema(); + public function dropAllSchema() : void; } diff --git a/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php b/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php index dd4b1ca5f40..605add99cc6 100644 --- a/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php +++ b/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php @@ -1,5 +1,7 @@ toSql($this->platform); } @@ -34,7 +36,7 @@ public function getCreateSchema(Schema $createSchema) /** * {@inheritdoc} */ - public function getUpdateSchema(Schema $toSchema, $noDrops = false) + public function getUpdateSchema(Schema $toSchema, bool $noDrops = false) : array { $comparator = new Comparator(); $sm = $this->conn->getSchemaManager(); @@ -52,7 +54,7 @@ public function getUpdateSchema(Schema $toSchema, $noDrops = false) /** * {@inheritdoc} */ - public function getDropSchema(Schema $dropSchema) + public function getDropSchema(Schema $dropSchema) : array { $visitor = new DropSchemaSqlCollector($this->platform); $sm = $this->conn->getSchemaManager(); @@ -112,7 +114,7 @@ public function getDropSchema(Schema $dropSchema) /** * {@inheritdoc} */ - public function getDropAllSchema() + public function getDropAllSchema() : array { $sm = $this->conn->getSchemaManager(); $visitor = new DropSchemaSqlCollector($this->platform); @@ -126,7 +128,7 @@ public function getDropAllSchema() /** * {@inheritdoc} */ - public function createSchema(Schema $createSchema) + public function createSchema(Schema $createSchema) : void { $this->processSql($this->getCreateSchema($createSchema)); } @@ -134,7 +136,7 @@ public function createSchema(Schema $createSchema) /** * {@inheritdoc} */ - public function updateSchema(Schema $toSchema, $noDrops = false) + public function updateSchema(Schema $toSchema, bool $noDrops = false) : void { $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); } @@ -142,7 +144,7 @@ public function updateSchema(Schema $toSchema, $noDrops = false) /** * {@inheritdoc} */ - public function dropSchema(Schema $dropSchema) + public function dropSchema(Schema $dropSchema) : void { $this->processSqlSafely($this->getDropSchema($dropSchema)); } @@ -150,7 +152,7 @@ public function dropSchema(Schema $dropSchema) /** * {@inheritdoc} */ - public function dropAllSchema() + public function dropAllSchema() : void { $this->processSql($this->getDropAllSchema()); } diff --git a/lib/Doctrine/DBAL/Schema/Table.php b/lib/Doctrine/DBAL/Schema/Table.php index af853c277d5..beca549dce5 100644 --- a/lib/Doctrine/DBAL/Schema/Table.php +++ b/lib/Doctrine/DBAL/Schema/Table.php @@ -1,17 +1,31 @@ $columns + * @param array $indexes + * @param array $uniqueConstraints + * @param array $fkConstraints + * @param array $options * * @throws DBALException */ - public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = []) - { + public function __construct( + string $tableName, + array $columns = [], + array $indexes = [], + array $uniqueConstraints = [], + array $fkConstraints = [], + array $options = [] + ) { if (strlen($tableName) === 0) { - throw DBALException::invalidTableName($tableName); + throw InvalidTableName::new($tableName); } $this->_setName($tableName); @@ -65,42 +87,28 @@ public function __construct($tableName, array $columns = [], array $indexes = [] $this->_addIndex($idx); } - foreach ($fkConstraints as $constraint) { - $this->_addForeignKeyConstraint($constraint); + foreach ($uniqueConstraints as $uniqueConstraint) { + $this->_addUniqueConstraint($uniqueConstraint); + } + + foreach ($fkConstraints as $fkConstraint) { + $this->_addForeignKeyConstraint($fkConstraint); } $this->_options = $options; } - /** - * @return void - */ - public function setSchemaConfig(SchemaConfig $schemaConfig) + public function setSchemaConfig(SchemaConfig $schemaConfig) : void { $this->_schemaConfig = $schemaConfig; } - /** - * @return int - */ - protected function _getMaxIdentifierLength() - { - if ($this->_schemaConfig instanceof SchemaConfig) { - return $this->_schemaConfig->getMaxIdentifierLength(); - } - - return 63; - } - /** * Sets the Primary Key. * - * @param string[] $columnNames - * @param string|false $indexName - * - * @return self + * @param array $columnNames */ - public function setPrimaryKey(array $columnNames, $indexName = false) + public function setPrimaryKey(array $columnNames, ?string $indexName = null) : self { $this->_addIndex($this->_createIndex($columnNames, $indexName ?: 'primary', true, true)); @@ -113,14 +121,29 @@ public function setPrimaryKey(array $columnNames, $indexName = false) } /** - * @param string[] $columnNames - * @param string|null $indexName - * @param string[] $flags - * @param mixed[] $options - * - * @return self + * @param array $columnNames + * @param array $flags + * @param array $options + */ + public function addUniqueConstraint(array $columnNames, ?string $indexName = null, array $flags = [], array $options = []) : self + { + if ($indexName === null) { + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $columnNames), + 'uniq', + $this->_getMaxIdentifierLength() + ); + } + + return $this->_addUniqueConstraint($this->_createUniqueConstraint($columnNames, $indexName, $flags, $options)); + } + + /** + * @param array $columnNames + * @param array $flags + * @param array $options */ - public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = []) + public function addIndex(array $columnNames, ?string $indexName = null, array $flags = [], array $options = []) : self { if ($indexName === null) { $indexName = $this->_generateIdentifierName( @@ -135,10 +158,8 @@ public function addIndex(array $columnNames, $indexName = null, array $flags = [ /** * Drops the primary key from this table. - * - * @return void */ - public function dropPrimaryKey() + public function dropPrimaryKey() : void { $this->dropIndex($this->_primaryKeyName); $this->_primaryKeyName = false; @@ -147,29 +168,24 @@ public function dropPrimaryKey() /** * Drops an index from this table. * - * @param string $indexName The index name. - * - * @return void - * * @throws SchemaException If the index does not exist. */ - public function dropIndex($indexName) + public function dropIndex(string $indexName) : void { $indexName = $this->normalizeIdentifier($indexName); + if (! $this->hasIndex($indexName)) { - throw SchemaException::indexDoesNotExist($indexName, $this->_name); + throw IndexDoesNotExist::new($indexName, $this->_name); } + unset($this->_indexes[$indexName]); } /** - * @param string[] $columnNames - * @param string|null $indexName - * @param mixed[] $options - * - * @return self + * @param array $columnNames + * @param array $options */ - public function addUniqueIndex(array $columnNames, $indexName = null, array $options = []) + public function addUniqueIndex(array $columnNames, ?string $indexName = null, array $options = []) : self { if ($indexName === null) { $indexName = $this->_generateIdentifierName( @@ -189,12 +205,10 @@ public function addUniqueIndex(array $columnNames, $indexName = null, array $opt * @param string|null $newIndexName The name of the index to rename to. * If null is given, the index name will be auto-generated. * - * @return self This table instance. - * * @throws SchemaException If no index exists for the given current name * or if an index with the given new name already exists on this table. */ - public function renameIndex($oldIndexName, $newIndexName = null) + public function renameIndex(string $oldIndexName, ?string $newIndexName = null) : self { $oldIndexName = $this->normalizeIdentifier($oldIndexName); $normalizedNewIndexName = $this->normalizeIdentifier($newIndexName); @@ -204,11 +218,11 @@ public function renameIndex($oldIndexName, $newIndexName = null) } if (! $this->hasIndex($oldIndexName)) { - throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name); + throw IndexDoesNotExist::new($oldIndexName, $this->_name); } if ($this->hasIndex($normalizedNewIndexName)) { - throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name); + throw IndexAlreadyExists::new($normalizedNewIndexName, $this->_name); } $oldIndex = $this->_indexes[$oldIndexName]; @@ -216,7 +230,7 @@ public function renameIndex($oldIndexName, $newIndexName = null) if ($oldIndex->isPrimary()) { $this->dropPrimaryKey(); - return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName ?? false); + return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName ?? null); } unset($this->_indexes[$oldIndexName]); @@ -231,11 +245,9 @@ public function renameIndex($oldIndexName, $newIndexName = null) /** * Checks if an index begins in the order of the given columns. * - * @param string[] $columnNames - * - * @return bool + * @param array $columnNames */ - public function columnsAreIndexed(array $columnNames) + public function columnsAreIndexed(array $columnNames) : bool { foreach ($this->getIndexes() as $index) { /** @var $index Index */ @@ -248,40 +260,9 @@ public function columnsAreIndexed(array $columnNames) } /** - * @param string[] $columnNames - * @param string $indexName - * @param bool $isUnique - * @param bool $isPrimary - * @param string[] $flags - * @param mixed[] $options - * - * @return Index - * - * @throws SchemaException - */ - private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = []) - { - if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { - throw SchemaException::indexNameInvalid($indexName); - } - - foreach ($columnNames as $columnName) { - if (! $this->hasColumn($columnName)) { - throw SchemaException::columnDoesNotExist($columnName, $this->_name); - } - } - - return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options); - } - - /** - * @param string $columnName - * @param string $typeName - * @param mixed[] $options - * - * @return Column + * @param array $options */ - public function addColumn($columnName, $typeName, array $options = []) + public function addColumn(string $columnName, string $typeName, array $options = []) : Column { $column = new Column($columnName, Type::getType($typeName), $options); @@ -290,34 +271,15 @@ public function addColumn($columnName, $typeName, array $options = []) return $column; } - /** - * Renames a Column. - * - * @deprecated - * - * @param string $oldColumnName - * @param string $newColumnName - * - * @throws DBALException - */ - public function renameColumn($oldColumnName, $newColumnName) - { - throw new DBALException('Table#renameColumn() was removed, because it drops and recreates ' . - 'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' . - 'column was renamed or one column was created and another one dropped.'); - } - /** * Change Column Details. * - * @param string $columnName - * @param mixed[] $options - * - * @return self + * @param array $options */ - public function changeColumn($columnName, array $options) + public function changeColumn(string $columnName, array $options) : self { $column = $this->getColumn($columnName); + $column->setOptions($options); return $this; @@ -325,14 +287,11 @@ public function changeColumn($columnName, array $options) /** * Drops a Column from the Table. - * - * @param string $columnName - * - * @return self */ - public function dropColumn($columnName) + public function dropColumn(string $columnName) : self { $columnName = $this->normalizeIdentifier($columnName); + unset($this->_columns[$columnName]); return $this; @@ -343,68 +302,32 @@ public function dropColumn($columnName) * * Name is inferred from the local columns. * - * @param Table|string $foreignTable Table schema instance or table name - * @param string[] $localColumnNames - * @param string[] $foreignColumnNames - * @param mixed[] $options - * @param string|null $constraintName - * - * @return self + * @param Table|string $foreignTable Table schema instance or table name + * @param array $localColumnNames + * @param array $foreignColumnNames + * @param array $options */ - public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], $constraintName = null) + public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], ?string $name = null) : self { - $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), 'fk', $this->_getMaxIdentifierLength()); - - return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options); - } - - /** - * Adds a foreign key constraint. - * - * Name is to be generated by the database itself. - * - * @deprecated Use {@link addForeignKeyConstraint} - * - * @param Table|string $foreignTable Table schema instance or table name - * @param string[] $localColumnNames - * @param string[] $foreignColumnNames - * @param mixed[] $options - * - * @return self - */ - public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = []) - { - return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options); - } + if (! $name) { + $name = $this->_generateIdentifierName( + array_merge((array) $this->getName(), $localColumnNames), + 'fk', + $this->_getMaxIdentifierLength() + ); + } - /** - * Adds a foreign key constraint with a given name. - * - * @deprecated Use {@link addForeignKeyConstraint} - * - * @param string $name - * @param Table|string $foreignTable Table schema instance or table name - * @param string[] $localColumnNames - * @param string[] $foreignColumnNames - * @param mixed[] $options - * - * @return self - * - * @throws SchemaException - */ - public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = []) - { if ($foreignTable instanceof Table) { foreach ($foreignColumnNames as $columnName) { if (! $foreignTable->hasColumn($columnName)) { - throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName()); + throw ColumnDoesNotExist::new($columnName, $foreignTable->getName()); } } } foreach ($localColumnNames as $columnName) { if (! $this->hasColumn($columnName)) { - throw SchemaException::columnDoesNotExist($columnName, $this->_name); + throw ColumnDoesNotExist::new($columnName, $this->_name); } } @@ -415,18 +338,14 @@ public function addNamedForeignKeyConstraint($name, $foreignTable, array $localC $name, $options ); - $this->_addForeignKeyConstraint($constraint); - return $this; + return $this->_addForeignKeyConstraint($constraint); } /** - * @param string $name - * @param mixed $value - * - * @return self + * @param mixed $value */ - public function addOption($name, $value) + public function addOption(string $name, $value) : self { $this->_options[$name] = $value; @@ -434,208 +353,124 @@ public function addOption($name, $value) } /** - * @return void - * - * @throws SchemaException + * Returns whether this table has a foreign key constraint with the given name. */ - protected function _addColumn(Column $column) + public function hasForeignKey(string $constraintName) : bool { - $columnName = $column->getName(); - $columnName = $this->normalizeIdentifier($columnName); - - if (isset($this->_columns[$columnName])) { - throw SchemaException::columnAlreadyExists($this->getName(), $columnName); - } + $constraintName = $this->normalizeIdentifier($constraintName); - $this->_columns[$columnName] = $column; + return isset($this->_fkConstraints[$constraintName]); } /** - * Adds an index to the table. - * - * @return self + * Returns the foreign key constraint with the given name. * - * @throws SchemaException + * @throws SchemaException If the foreign key does not exist. */ - protected function _addIndex(Index $indexCandidate) + public function getForeignKey(string $constraintName) : ForeignKeyConstraint { - $indexName = $indexCandidate->getName(); - $indexName = $this->normalizeIdentifier($indexName); - $replacedImplicitIndexes = []; - - foreach ($this->implicitIndexes as $name => $implicitIndex) { - if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { - continue; - } - - $replacedImplicitIndexes[] = $name; - } - - if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || - ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) - ) { - throw SchemaException::indexAlreadyExists($indexName, $this->_name); - } - - foreach ($replacedImplicitIndexes as $name) { - unset($this->_indexes[$name], $this->implicitIndexes[$name]); - } + $constraintName = $this->normalizeIdentifier($constraintName); - if ($indexCandidate->isPrimary()) { - $this->_primaryKeyName = $indexName; + if (! $this->hasForeignKey($constraintName)) { + throw ForeignKeyDoesNotExist::new($constraintName, $this->_name); } - $this->_indexes[$indexName] = $indexCandidate; - - return $this; + return $this->_fkConstraints[$constraintName]; } /** - * @return void + * Removes the foreign key constraint with the given name. + * + * @throws SchemaException */ - protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) + public function removeForeignKey(string $constraintName) : void { - $constraint->setLocalTable($this); - - if (strlen($constraint->getName())) { - $name = $constraint->getName(); - } else { - $name = $this->_generateIdentifierName( - array_merge((array) $this->getName(), $constraint->getLocalColumns()), - 'fk', - $this->_getMaxIdentifierLength() - ); - } - $name = $this->normalizeIdentifier($name); - - $this->_fkConstraints[$name] = $constraint; - - // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request. - // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes - // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns). - $indexName = $this->_generateIdentifierName( - array_merge([$this->getName()], $constraint->getColumns()), - 'idx', - $this->_getMaxIdentifierLength() - ); - $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); + $constraintName = $this->normalizeIdentifier($constraintName); - foreach ($this->_indexes as $existingIndex) { - if ($indexCandidate->isFullfilledBy($existingIndex)) { - return; - } + if (! $this->hasForeignKey($constraintName)) { + throw ForeignKeyDoesNotExist::new($constraintName, $this->_name); } - $this->_addIndex($indexCandidate); - $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + unset($this->_fkConstraints[$constraintName]); } /** - * Returns whether this table has a foreign key constraint with the given name. - * - * @param string $constraintName - * - * @return bool + * Returns whether this table has a unique constraint with the given name. */ - public function hasForeignKey($constraintName) + public function hasUniqueConstraint(string $constraintName) : bool { $constraintName = $this->normalizeIdentifier($constraintName); - return isset($this->_fkConstraints[$constraintName]); + return isset($this->_uniqueConstraints[$constraintName]); } /** - * Returns the foreign key constraint with the given name. - * - * @param string $constraintName The constraint name. - * - * @return ForeignKeyConstraint + * Returns the unique constraint with the given name. * * @throws SchemaException If the foreign key does not exist. */ - public function getForeignKey($constraintName) + public function getUniqueConstraint(string $constraintName) : UniqueConstraint { $constraintName = $this->normalizeIdentifier($constraintName); - if (! $this->hasForeignKey($constraintName)) { - throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + + if (! $this->hasUniqueConstraint($constraintName)) { + throw UniqueConstraintDoesNotExist::new($constraintName, $this->_name); } - return $this->_fkConstraints[$constraintName]; + return $this->_uniqueConstraints[$constraintName]; } /** - * Removes the foreign key constraint with the given name. - * - * @param string $constraintName The constraint name. - * - * @return void + * Removes the unique constraint with the given name. * * @throws SchemaException */ - public function removeForeignKey($constraintName) + public function removeUniqueConstraint(string $constraintName) : void { $constraintName = $this->normalizeIdentifier($constraintName); - if (! $this->hasForeignKey($constraintName)) { - throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + + if (! $this->hasUniqueConstraint($constraintName)) { + throw UniqueConstraintDoesNotExist::new($constraintName, $this->_name); } - unset($this->_fkConstraints[$constraintName]); + unset($this->_uniqueConstraints[$constraintName]); } /** * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest) * - * @return Column[] + * @return array */ - public function getColumns() + public function getColumns() : array { - $primaryKey = $this->getPrimaryKey(); - $primaryKeyColumns = []; + $columns = $this->_columns; + $pkCols = []; + $fkCols = []; + + $primaryKey = $this->getPrimaryKey(); if ($primaryKey !== null) { - $primaryKeyColumns = $this->filterColumns($primaryKey->getColumns()); + $pkCols = $primaryKey->getColumns(); } - return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns); - } - - /** - * Returns foreign key columns - * - * @return Column[] - */ - private function getForeignKeyColumns() - { - $foreignKeyColumns = []; - foreach ($this->getForeignKeys() as $foreignKey) { - $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns()); + foreach ($this->getForeignKeys() as $fk) { + /** @var ForeignKeyConstraint $fk */ + $fkCols = array_merge($fkCols, $fk->getColumns()); } - return $this->filterColumns($foreignKeyColumns); - } + $colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns))); - /** - * Returns only columns that have specified names - * - * @param string[] $columnNames - * - * @return Column[] - */ - private function filterColumns(array $columnNames) - { - return array_filter($this->_columns, static function ($columnName) use ($columnNames) { - return in_array($columnName, $columnNames, true); - }, ARRAY_FILTER_USE_KEY); + uksort($columns, static function ($a, $b) use ($colNames) : bool { + return array_search($a, $colNames) >= array_search($b, $colNames); + }); + + return $columns; } /** * Returns whether this table has a Column with the given name. - * - * @param string $columnName The column name. - * - * @return bool */ - public function hasColumn($columnName) + public function hasColumn(string $columnName) : bool { $columnName = $this->normalizeIdentifier($columnName); @@ -645,17 +480,14 @@ public function hasColumn($columnName) /** * Returns the Column with the given name. * - * @param string $columnName The column name. - * - * @return Column - * * @throws SchemaException If the column does not exist. */ - public function getColumn($columnName) + public function getColumn(string $columnName) : Column { $columnName = $this->normalizeIdentifier($columnName); + if (! $this->hasColumn($columnName)) { - throw SchemaException::columnDoesNotExist($columnName, $this->_name); + throw ColumnDoesNotExist::new($columnName, $this->_name); } return $this->_columns[$columnName]; @@ -663,31 +495,27 @@ public function getColumn($columnName) /** * Returns the primary key. - * - * @return Index|null The primary key, or null if this Table has no primary key. */ - public function getPrimaryKey() + public function getPrimaryKey() : ?Index { - if (! $this->hasPrimaryKey()) { - return null; - } - - return $this->getIndex($this->_primaryKeyName); + return $this->hasPrimaryKey() + ? $this->getIndex($this->_primaryKeyName) + : null; } /** * Returns the primary key columns. * - * @return string[] + * @return array * * @throws DBALException */ - public function getPrimaryKeyColumns() + public function getPrimaryKeyColumns() : array { $primaryKey = $this->getPrimaryKey(); if ($primaryKey === null) { - throw new DBALException('Table ' . $this->getName() . ' has no primary key.'); + throw new DBALException(sprintf('Table "%s" has no primary key.', $this->getName())); } return $primaryKey->getColumns(); @@ -695,22 +523,16 @@ public function getPrimaryKeyColumns() /** * Returns whether this table has a primary key. - * - * @return bool */ - public function hasPrimaryKey() + public function hasPrimaryKey() : bool { return $this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName); } /** * Returns whether this table has an Index with the given name. - * - * @param string $indexName The index name. - * - * @return bool */ - public function hasIndex($indexName) + public function hasIndex(string $indexName) : bool { $indexName = $this->normalizeIdentifier($indexName); @@ -720,72 +542,69 @@ public function hasIndex($indexName) /** * Returns the Index with the given name. * - * @param string $indexName The index name. - * - * @return Index - * * @throws SchemaException If the index does not exist. */ - public function getIndex($indexName) + public function getIndex(string $indexName) : Index { $indexName = $this->normalizeIdentifier($indexName); + if (! $this->hasIndex($indexName)) { - throw SchemaException::indexDoesNotExist($indexName, $this->_name); + throw IndexDoesNotExist::new($indexName, $this->_name); } return $this->_indexes[$indexName]; } /** - * @return Index[] + * @return array */ - public function getIndexes() + public function getIndexes() : array { return $this->_indexes; } /** - * Returns the foreign key constraints. + * Returns the unique constraints. * - * @return ForeignKeyConstraint[] + * @return array */ - public function getForeignKeys() + public function getUniqueConstraints() : array { - return $this->_fkConstraints; + return $this->_uniqueConstraints; } /** - * @param string $name + * Returns the foreign key constraints. * - * @return bool + * @return array */ - public function hasOption($name) + public function getForeignKeys() : array + { + return $this->_fkConstraints; + } + + public function hasOption(string $name) : bool { return isset($this->_options[$name]); } /** - * @param string $name - * * @return mixed */ - public function getOption($name) + public function getOption(string $name) { return $this->_options[$name]; } /** - * @return mixed[] + * @return array */ - public function getOptions() + public function getOptions() : array { return $this->_options; } - /** - * @return void - */ - public function visit(Visitor $visitor) + public function visit(Visitor $visitor) : void { $visitor->acceptTable($this); @@ -804,33 +623,165 @@ public function visit(Visitor $visitor) /** * Clone of a Table triggers a deep clone of all affected assets. - * - * @return void */ public function __clone() { foreach ($this->_columns as $k => $column) { $this->_columns[$k] = clone $column; } + foreach ($this->_indexes as $k => $index) { $this->_indexes[$k] = clone $index; } + foreach ($this->_fkConstraints as $k => $fk) { $this->_fkConstraints[$k] = clone $fk; $this->_fkConstraints[$k]->setLocalTable($this); } } + protected function _getMaxIdentifierLength() : int + { + return $this->_schemaConfig instanceof SchemaConfig + ? $this->_schemaConfig->getMaxIdentifierLength() + : 63; + } + + /** + * @throws SchemaException + */ + protected function _addColumn(Column $column) : void + { + $columnName = $column->getName(); + $columnName = $this->normalizeIdentifier($columnName); + + if (isset($this->_columns[$columnName])) { + throw ColumnAlreadyExists::new($this->getName(), $columnName); + } + + $this->_columns[$columnName] = $column; + } + + /** + * Adds an index to the table. + * + * @throws SchemaException + */ + protected function _addIndex(Index $indexCandidate) : self + { + $indexName = $indexCandidate->getName(); + $indexName = $this->normalizeIdentifier($indexName); + $replacedImplicitIndexes = []; + + foreach ($this->implicitIndexes as $name => $implicitIndex) { + if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { + continue; + } + + $replacedImplicitIndexes[] = $name; + } + + if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || + ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) + ) { + throw IndexAlreadyExists::new($indexName, $this->_name); + } + + foreach ($replacedImplicitIndexes as $name) { + unset($this->_indexes[$name], $this->implicitIndexes[$name]); + } + + if ($indexCandidate->isPrimary()) { + $this->_primaryKeyName = $indexName; + } + + $this->_indexes[$indexName] = $indexCandidate; + + return $this; + } + + protected function _addUniqueConstraint(UniqueConstraint $constraint) : self + { + $name = strlen($constraint->getName()) + ? $constraint->getName() + : $this->_generateIdentifierName( + array_merge((array) $this->getName(), $constraint->getColumns()), + 'fk', + $this->_getMaxIdentifierLength() + ); + + $name = $this->normalizeIdentifier($name); + + $this->_uniqueConstraints[$name] = $constraint; + + // If there is already an index that fulfills this requirements drop the request. In the case of __construct + // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. + // This creates computation overhead in this case, however no duplicate indexes are ever added (column based). + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $constraint->getColumns()), + 'idx', + $this->_getMaxIdentifierLength() + ); + + $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, true, false); + + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return $this; + } + } + + $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + + return $this; + } + + protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) : self + { + $constraint->setLocalTable($this); + + $name = strlen($constraint->getName()) + ? $constraint->getName() + : $this->_generateIdentifierName( + array_merge((array) $this->getName(), $constraint->getLocalColumns()), + 'fk', + $this->_getMaxIdentifierLength() + ); + + $name = $this->normalizeIdentifier($name); + + $this->_fkConstraints[$name] = $constraint; + + // add an explicit index on the foreign key columns. + // If there is already an index that fulfills this requirements drop the request. In the case of __construct + // calling this method during hydration from schema-details all the explicitly added indexes lead to duplicates. + // This creates computation overhead in this case, however no duplicate indexes are ever added (column based). + $indexName = $this->_generateIdentifierName( + array_merge([$this->getName()], $constraint->getColumns()), + 'idx', + $this->_getMaxIdentifierLength() + ); + + $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); + + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return $this; + } + } + + $this->_addIndex($indexCandidate); + $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; + + return $this; + } + /** * Normalizes a given identifier. * * Trims quotes and lowercases the given identifier. - * - * @param string|null $identifier The identifier to normalize. - * - * @return string The normalized identifier. */ - private function normalizeIdentifier($identifier) + private function normalizeIdentifier(?string $identifier) : string { if ($identifier === null) { return ''; @@ -838,4 +789,60 @@ private function normalizeIdentifier($identifier) return $this->trimQuotes(strtolower($identifier)); } + + /** + * @param array $columns + * @param array $flags + * @param array $options + * + * @throws SchemaException + */ + private function _createUniqueConstraint(array $columns, string $indexName, array $flags = [], array $options = []) : UniqueConstraint + { + if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { + throw IndexNameInvalid::new($indexName); + } + + foreach ($columns as $index => $value) { + if (is_string($index)) { + $columnName = $index; + } else { + $columnName = $value; + } + + if (! $this->hasColumn($columnName)) { + throw ColumnDoesNotExist::new($columnName, $this->_name); + } + } + + return new UniqueConstraint($indexName, $columns, $flags, $options); + } + + /** + * @param array $columns + * @param array $flags + * @param array $options + * + * @throws SchemaException + */ + private function _createIndex(array $columns, string $indexName, bool $isUnique, bool $isPrimary, array $flags = [], array $options = []) : Index + { + if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { + throw IndexNameInvalid::new($indexName); + } + + foreach ($columns as $index => $value) { + if (is_string($index)) { + $columnName = $index; + } else { + $columnName = $value; + } + + if (! $this->hasColumn($columnName)) { + throw ColumnDoesNotExist::new($columnName, $this->_name); + } + } + + return new Index($indexName, $columns, $isUnique, $isPrimary, $flags, $options); + } } diff --git a/lib/Doctrine/DBAL/Schema/TableDiff.php b/lib/Doctrine/DBAL/Schema/TableDiff.php index 1ff2c0ad105..0a8cf138a09 100644 --- a/lib/Doctrine/DBAL/Schema/TableDiff.php +++ b/lib/Doctrine/DBAL/Schema/TableDiff.php @@ -1,5 +1,7 @@ */ public $addedColumns; /** * All changed fields. * - * @var ColumnDiff[] + * @var array */ public $changedColumns = []; /** * All removed fields. * - * @var Column[] + * @var array */ public $removedColumns = []; /** * Columns that are only renamed from key to column instance name. * - * @var Column[] + * @var array */ public $renamedColumns = []; /** * All added indexes. * - * @var Index[] + * @var array */ public $addedIndexes = []; /** * All changed indexes. * - * @var Index[] + * @var array */ public $changedIndexes = []; /** * All removed indexes * - * @var Index[] + * @var array */ public $removedIndexes = []; /** * Indexes that are only renamed but are identical otherwise. * - * @var Index[] + * @var array */ public $renamedIndexes = []; /** * All added foreign key definitions * - * @var ForeignKeyConstraint[] + * @var array */ public $addedForeignKeys = []; /** * All changed foreign keys * - * @var ForeignKeyConstraint[] + * @var array */ public $changedForeignKeys = []; /** * All removed foreign keys * - * @var ForeignKeyConstraint[]|string[] + * @var array */ public $removedForeignKeys = []; @@ -98,22 +100,21 @@ class TableDiff /** * Constructs an TableDiff object. * - * @param string $tableName - * @param Column[] $addedColumns - * @param ColumnDiff[] $changedColumns - * @param Column[] $removedColumns - * @param Index[] $addedIndexes - * @param Index[] $changedIndexes - * @param Index[] $removedIndexes + * @param array $addedColumns + * @param array $changedColumns + * @param array $removedColumns + * @param array $addedIndexes + * @param array $changedIndexes + * @param array $removedIndexes */ public function __construct( - $tableName, - $addedColumns = [], - $changedColumns = [], - $removedColumns = [], - $addedIndexes = [], - $changedIndexes = [], - $removedIndexes = [], + string $tableName, + array $addedColumns = [], + array $changedColumns = [], + array $removedColumns = [], + array $addedIndexes = [], + array $changedIndexes = [], + array $removedIndexes = [], ?Table $fromTable = null ) { $this->name = $tableName; @@ -128,23 +129,18 @@ public function __construct( /** * @param AbstractPlatform $platform The platform to use for retrieving this table diff's name. - * - * @return Identifier */ - public function getName(AbstractPlatform $platform) + public function getName(AbstractPlatform $platform) : Identifier { return new Identifier( $this->fromTable instanceof Table ? $this->fromTable->getQuotedName($platform) : $this->name ); } - /** - * @return Identifier|false - */ - public function getNewName() + public function getNewName() : ?Identifier { - if ($this->newName === false) { - return false; + if ($this->newName === null) { + return null; } return new Identifier($this->newName); diff --git a/lib/Doctrine/DBAL/Schema/UniqueConstraint.php b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php new file mode 100644 index 00000000000..75d6f76b391 --- /dev/null +++ b/lib/Doctrine/DBAL/Schema/UniqueConstraint.php @@ -0,0 +1,151 @@ + + */ + protected $columns = []; + + /** + * Platform specific flags + * + * @var array + */ + protected $flags = []; + + /** + * Platform specific options + * + * @var array + */ + private $options = []; + + /** + * @param array $columns + * @param array $flags + * @param array $options + */ + public function __construct(string $indexName, array $columns, array $flags = [], array $options = []) + { + $this->_setName($indexName); + + $this->options = $options; + + foreach ($columns as $column) { + $this->_addColumn($column); + } + + foreach ($flags as $flag) { + $this->addFlag($flag); + } + } + + /** + * {@inheritdoc} + */ + public function getColumns() : array + { + return array_keys($this->columns); + } + + /** + * {@inheritdoc} + */ + public function getQuotedColumns(AbstractPlatform $platform) : array + { + $columns = []; + + foreach ($this->columns as $column) { + $columns[] = $column->getQuotedName($platform); + } + + return $columns; + } + + /** + * @return array + */ + public function getUnquotedColumns() : array + { + return array_map([$this, 'trimQuotes'], $this->getColumns()); + } + + /** + * Returns platform specific flags for unique constraint. + * + * @return array + */ + public function getFlags() : array + { + return array_keys($this->flags); + } + + /** + * Adds flag for a unique constraint that translates to platform specific handling. + * + * @example $uniqueConstraint->addFlag('CLUSTERED') + */ + public function addFlag(string $flag) : self + { + $this->flags[strtolower($flag)] = true; + + return $this; + } + + /** + * Does this unique constraint have a specific flag? + */ + public function hasFlag(string $flag) : bool + { + return isset($this->flags[strtolower($flag)]); + } + + /** + * Removes a flag. + */ + public function removeFlag(string $flag) : void + { + unset($this->flags[strtolower($flag)]); + } + + public function hasOption(string $name) : bool + { + return isset($this->options[strtolower($name)]); + } + + /** + * @return mixed + */ + public function getOption(string $name) + { + return $this->options[strtolower($name)]; + } + + /** + * @return array + */ + public function getOptions() : array + { + return $this->options; + } + + protected function _addColumn(string $column) : void + { + $this->columns[$column] = new Identifier($column); + } +} diff --git a/lib/Doctrine/DBAL/Schema/View.php b/lib/Doctrine/DBAL/Schema/View.php index ac8d6cb5cb4..f67b203036e 100644 --- a/lib/Doctrine/DBAL/Schema/View.php +++ b/lib/Doctrine/DBAL/Schema/View.php @@ -1,5 +1,7 @@ _setName($name); $this->sql = $sql; } - /** - * @return string - */ - public function getSql() + public function getSql() : string { return $this->sql; } diff --git a/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php b/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php index 47169044274..bb3abff57f9 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php @@ -1,5 +1,7 @@ */ private $createNamespaceQueries = []; - /** @var string[] */ + /** @var array */ private $createTableQueries = []; - /** @var string[] */ + /** @var array */ private $createSequenceQueries = []; - /** @var string[] */ + /** @var array */ private $createFkConstraintQueries = []; /** @var AbstractPlatform */ @@ -33,7 +35,7 @@ public function __construct(AbstractPlatform $platform) /** * {@inheritdoc} */ - public function acceptNamespace($namespaceName) + public function acceptNamespace(string $namespaceName) : void { if (! $this->platform->supportsSchemas()) { return; @@ -45,7 +47,7 @@ public function acceptNamespace($namespaceName) /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { $this->createTableQueries = array_merge($this->createTableQueries, $this->platform->getCreateTableSQL($table)); } @@ -53,7 +55,7 @@ public function acceptTable(Table $table) /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { if (! $this->platform->supportsForeignKeyConstraints()) { return; @@ -65,15 +67,12 @@ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkCons /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { $this->createSequenceQueries[] = $this->platform->getCreateSequenceSQL($sequence); } - /** - * @return void - */ - public function resetQueries() + public function resetQueries() : void { $this->createNamespaceQueries = []; $this->createTableQueries = []; @@ -84,9 +83,9 @@ public function resetQueries() /** * Gets all queries collected so far. * - * @return string[] + * @return array */ - public function getQueries() + public function getQueries() : array { return array_merge( $this->createNamespaceQueries, diff --git a/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php b/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php index 81e2023128b..f51b547a44a 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php @@ -1,10 +1,12 @@ tables->attach($table); } @@ -44,10 +46,10 @@ public function acceptTable(Table $table) /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { if (strlen($fkConstraint->getName()) === 0) { - throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint); + throw NamedForeignKeyRequired::new($localTable, $fkConstraint); } $this->constraints->attach($fkConstraint, $localTable); @@ -56,15 +58,12 @@ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkCons /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { $this->sequences->attach($sequence); } - /** - * @return void - */ - public function clearQueries() + public function clearQueries() : void { $this->constraints = new SplObjectStorage(); $this->sequences = new SplObjectStorage(); @@ -72,9 +71,9 @@ public function clearQueries() } /** - * @return string[] + * @return array */ - public function getQueries() + public function getQueries() : array { $sql = []; diff --git a/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php b/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php index d5e94cf6ea3..3f81b5c217c 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php @@ -1,5 +1,7 @@ output .= $this->createNodeRelation( $fkConstraint->getLocalTableName() . ':col' . current($fkConstraint->getLocalColumns()) . ':se', @@ -37,7 +39,7 @@ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkCons /** * {@inheritdoc} */ - public function acceptSchema(Schema $schema) + public function acceptSchema(Schema $schema) : void { $this->output = 'digraph "' . $schema->getName() . '" {' . "\n"; $this->output .= 'splines = true;' . "\n"; @@ -50,7 +52,7 @@ public function acceptSchema(Schema $schema) /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { $this->output .= $this->createNode( $table->getName(), @@ -61,10 +63,7 @@ public function acceptTable(Table $table) ); } - /** - * @return string - */ - private function createTableLabel(Table $table) + private function createTableLabel(Table $table) : string { // Start the table $label = '<
'; @@ -79,7 +78,7 @@ private function createTableLabel(Table $table) $label .= ''; $label .= ''; + $label .= ''; $label .= '
'; $label .= '' . $columnLabel . ''; - $label .= '' . strtolower($column->getType()) . '' . strtolower($column->getType()->getName()) . ''; $primaryKey = $table->getPrimaryKey(); @@ -97,12 +96,9 @@ private function createTableLabel(Table $table) } /** - * @param string $name - * @param string[] $options - * - * @return string + * @param array $options */ - private function createNode($name, $options) + private function createNode(string $name, array $options) : string { $node = $name . ' ['; foreach ($options as $key => $value) { @@ -114,13 +110,9 @@ private function createNode($name, $options) } /** - * @param string $node1 - * @param string $node2 - * @param string[] $options - * - * @return string + * @param array $options */ - private function createNodeRelation($node1, $node2, $options) + private function createNodeRelation(string $node1, string $node2, array $options) : string { $relation = $node1 . ' -> ' . $node2 . ' ['; foreach ($options as $key => $value) { @@ -133,10 +125,8 @@ private function createNodeRelation($node1, $node2, $options) /** * Get Graphviz Output - * - * @return string */ - public function getOutput() + public function getOutput() : string { return $this->output . '}'; } @@ -148,12 +138,8 @@ public function getOutput() * and execute: * * neato -Tpng -o er.png er.dot - * - * @param string $filename - * - * @return void */ - public function write($filename) + public function write(string $filename) : void { file_put_contents($filename, $this->getOutput()); } diff --git a/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php b/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php index 186fe1b4213..90e10b91b70 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php @@ -1,5 +1,7 @@ schema = $schema; } @@ -34,7 +36,7 @@ public function acceptSchema(Schema $schema) /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { if ($table->isInDefaultNamespace($this->schema->getName())) { return; @@ -46,7 +48,7 @@ public function acceptTable(Table $table) /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { if ($sequence->isInDefaultNamespace($this->schema->getName())) { return; @@ -58,7 +60,7 @@ public function acceptSequence(Sequence $sequence) /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { // The table may already be deleted in a previous // RemoveNamespacedAssets#acceptTable call. Removing Foreign keys that diff --git a/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php b/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php index 5ec843d9be6..77c7670bff7 100644 --- a/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php +++ b/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php @@ -1,5 +1,7 @@ |array */ private $activeConnections = []; /** @var string|int|null */ private $activeShardId; - /** @var mixed[] */ + /** @var array>|array> */ private $connectionParameters = []; /** @@ -64,14 +67,18 @@ class PoolingShardConnection extends Connection * * @throws InvalidArgumentException */ - public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null) - { + public function __construct( + array $params, + Driver $driver, + ?Configuration $config = null, + ?EventManager $eventManager = null + ) { if (! isset($params['global'], $params['shards'])) { - throw new InvalidArgumentException("Connection Parameters require 'global' and 'shards' configurations."); + throw new InvalidArgumentException('Connection Parameters require "global" and "shards" configurations.'); } if (! isset($params['shardChoser'])) { - throw new InvalidArgumentException("Missing Shard Choser configuration 'shardChoser'"); + throw new InvalidArgumentException('Missing Shard Choser configuration "shardChoser".'); } if (is_string($params['shardChoser'])) { @@ -79,14 +86,14 @@ public function __construct(array $params, Driver $driver, ?Configuration $confi } if (! ($params['shardChoser'] instanceof ShardChoser)) { - throw new InvalidArgumentException("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); + throw new InvalidArgumentException('The "shardChoser" configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser'); } $this->connectionParameters[0] = array_merge($params, $params['global']); foreach ($params['shards'] as $shard) { if (! isset($shard['id'])) { - throw new InvalidArgumentException("Missing 'id' for one configured shard. Please specify a unique shard-id."); + throw new InvalidArgumentException('Missing "id" for one configured shard. Please specify a unique shard-id.'); } if (! is_numeric($shard['id']) || $shard['id'] < 1) { @@ -94,7 +101,7 @@ public function __construct(array $params, Driver $driver, ?Configuration $confi } if (isset($this->connectionParameters[$shard['id']])) { - throw new InvalidArgumentException('Shard ' . $shard['id'] . ' is duplicated in the configuration.'); + throw new InvalidArgumentException(sprintf('Shard "%s" is duplicated in the configuration.', $shard['id'])); } $this->connectionParameters[$shard['id']] = array_merge($params, $shard); @@ -116,68 +123,26 @@ public function getActiveShardId() /** * {@inheritdoc} */ - public function getParams() + public function getParams() : array { return $this->activeShardId ? $this->connectionParameters[$this->activeShardId] : $this->connectionParameters[0]; } - /** - * {@inheritdoc} - */ - public function getHost() - { - $params = $this->getParams(); - - return $params['host'] ?? parent::getHost(); - } - - /** - * {@inheritdoc} - */ - public function getPort() - { - $params = $this->getParams(); - - return $params['port'] ?? parent::getPort(); - } - - /** - * {@inheritdoc} - */ - public function getUsername() - { - $params = $this->getParams(); - - return $params['user'] ?? parent::getUsername(); - } - - /** - * {@inheritdoc} - */ - public function getPassword() - { - $params = $this->getParams(); - - return $params['password'] ?? parent::getPassword(); - } - /** * Connects to a given shard. * * @param string|int|null $shardId * - * @return bool - * * @throws ShardingException */ - public function connect($shardId = null) + public function connect($shardId = null) : void { if ($shardId === null && $this->_conn) { - return false; + return; } if ($shardId !== null && $shardId === $this->activeShardId) { - return false; + return; } if ($this->getTransactionNestingLevel() > 0) { @@ -189,27 +154,25 @@ public function connect($shardId = null) if (isset($this->activeConnections[$activeShardId])) { $this->_conn = $this->activeConnections[$activeShardId]; - return false; + return; } $this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId); - if ($this->_eventManager->hasListeners(Events::postConnect)) { - $eventArgs = new ConnectionEventArgs($this); - $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + if (! $this->_eventManager->hasListeners(Events::postConnect)) { + return; } - return true; + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } /** * Connects to a specific connection. * * @param string|int $shardId - * - * @return \Doctrine\DBAL\Driver\Connection */ - protected function connectTo($shardId) + protected function connectTo($shardId) : DriverConnection { $params = $this->getParams(); @@ -217,18 +180,16 @@ protected function connectTo($shardId) $connectionParams = $this->connectionParameters[$shardId]; - $user = $connectionParams['user'] ?? null; - $password = $connectionParams['password'] ?? null; + $user = $connectionParams['user'] ?? ''; + $password = $connectionParams['password'] ?? ''; return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); } /** * @param string|int|null $shardId - * - * @return bool */ - public function isConnected($shardId = null) + public function isConnected($shardId = null) : bool { if ($shardId === null) { return $this->_conn !== null; @@ -237,10 +198,7 @@ public function isConnected($shardId = null) return isset($this->activeConnections[$shardId]); } - /** - * @return void - */ - public function close() + public function close() : void { $this->_conn = null; $this->activeConnections = []; diff --git a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php b/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php index 5edc56b8778..5a21944d303 100644 --- a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php +++ b/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php @@ -1,5 +1,7 @@ conn->connect(0); $this->currentDistributionValue = null; @@ -38,7 +40,7 @@ public function selectGlobal() /** * {@inheritDoc} */ - public function selectShard($distributionValue) + public function selectShard($distributionValue) : void { $shardId = $this->choser->pickShard($distributionValue, $this->conn); $this->conn->connect($shardId); @@ -56,7 +58,7 @@ public function getCurrentDistributionValue() /** * {@inheritDoc} */ - public function getShards() + public function getShards() : array { $params = $this->conn->getParams(); $shards = []; @@ -73,7 +75,7 @@ public function getShards() * * @throws RuntimeException */ - public function queryAll($sql, array $params, array $types) + public function queryAll(string $sql, array $params, array $types) : array { $shards = $this->getShards(); if (! $shards) { diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php index 417f674a3e0..343b941a6ec 100644 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php +++ b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php @@ -1,5 +1,7 @@ work($toSchema, static function ($synchronizer, $schema) use ($noDrops) { return $synchronizer->getUpdateSchema($schema, $noDrops); @@ -81,7 +83,7 @@ public function getUpdateSchema(Schema $toSchema, $noDrops = false) /** * {@inheritdoc} */ - public function getDropSchema(Schema $dropSchema) + public function getDropSchema(Schema $dropSchema) : array { return $this->work($dropSchema, static function ($synchronizer, $schema) { return $synchronizer->getDropSchema($schema); @@ -91,7 +93,7 @@ public function getDropSchema(Schema $dropSchema) /** * {@inheritdoc} */ - public function createSchema(Schema $createSchema) + public function createSchema(Schema $createSchema) : void { $this->processSql($this->getCreateSchema($createSchema)); } @@ -99,7 +101,7 @@ public function createSchema(Schema $createSchema) /** * {@inheritdoc} */ - public function updateSchema(Schema $toSchema, $noDrops = false) + public function updateSchema(Schema $toSchema, bool $noDrops = false) : void { $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); } @@ -107,7 +109,7 @@ public function updateSchema(Schema $toSchema, $noDrops = false) /** * {@inheritdoc} */ - public function dropSchema(Schema $dropSchema) + public function dropSchema(Schema $dropSchema) : void { $this->processSqlSafely($this->getDropSchema($dropSchema)); } @@ -115,7 +117,7 @@ public function dropSchema(Schema $dropSchema) /** * {@inheritdoc} */ - public function getDropAllSchema() + public function getDropAllSchema() : array { $this->shardManager->selectGlobal(); $globalSql = $this->synchronizer->getDropAllSchema(); @@ -148,7 +150,7 @@ public function getDropAllSchema() /** * {@inheritdoc} */ - public function dropAllSchema() + public function dropAllSchema() : void { $this->processSqlSafely($this->getDropAllSchema()); } @@ -156,7 +158,7 @@ public function dropAllSchema() /** * @return Schema[] */ - private function partitionSchema(Schema $schema) + private function partitionSchema(Schema $schema) : array { return [ $this->extractSchemaFederation($schema, false), @@ -165,13 +167,9 @@ private function partitionSchema(Schema $schema) } /** - * @param bool $isFederation - * - * @return Schema - * * @throws RuntimeException */ - private function extractSchemaFederation(Schema $schema, $isFederation) + private function extractSchemaFederation(Schema $schema, bool $isFederation) : Schema { $partitionedSchema = clone $schema; @@ -202,7 +200,7 @@ private function extractSchemaFederation(Schema $schema, $isFederation) * * @return string[] */ - private function work(Schema $schema, Closure $operation) + private function work(Schema $schema, Closure $operation) : array { [$global, $federation] = $this->partitionSchema($schema); $sql = []; @@ -233,10 +231,7 @@ private function work(Schema $schema, Closure $operation) return $sql; } - /** - * @return string - */ - private function getFederationTypeDefaultValue() + private function getFederationTypeDefaultValue() : string { $federationType = Type::getType($this->shardManager->getDistributionType()); @@ -257,10 +252,7 @@ private function getFederationTypeDefaultValue() return $defaultValue; } - /** - * @return string - */ - private function getCreateFederationStatement() + private function getCreateFederationStatement() : string { $federationType = Type::getType($this->shardManager->getDistributionType()); $federationTypeSql = $federationType->getSQLDeclaration([], $this->conn->getDatabasePlatform()); diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php index d8178ee07db..0b00e9ade13 100644 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php +++ b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php @@ -1,11 +1,16 @@ getParams(); if (! isset($params['sharding']['federationName'])) { - throw ShardingException::missingDefaultFederationName(); + throw MissingDefaultFederationName::new(); } if (! isset($params['sharding']['distributionKey'])) { - throw ShardingException::missingDefaultDistributionKey(); + throw MissingDefaultDistributionKey::new(); } if (! isset($params['sharding']['distributionType'])) { - throw ShardingException::missingDistributionType(); + throw MissingDistributionType::new(); } $this->federationName = $params['sharding']['federationName']; @@ -60,53 +65,43 @@ public function __construct(Connection $conn) /** * Gets the name of the federation. - * - * @return string */ - public function getFederationName() + public function getFederationName() : string { return $this->federationName; } /** * Gets the distribution key. - * - * @return string */ - public function getDistributionKey() + public function getDistributionKey() : string { return $this->distributionKey; } /** * Gets the Doctrine Type name used for the distribution. - * - * @return string */ - public function getDistributionType() + public function getDistributionType() : string { return $this->distributionType; } /** * Sets Enabled/Disable filtering on the fly. - * - * @param bool $flag - * - * @return void */ - public function setFilteringEnabled($flag) + public function setFilteringEnabled(bool $flag) : void { - $this->filteringEnabled = (bool) $flag; + $this->filteringEnabled = $flag; } /** * {@inheritDoc} */ - public function selectGlobal() + public function selectGlobal() : void { if ($this->conn->isTransactionActive()) { - throw ShardingException::activeTransaction(); + throw ActiveTransaction::new(); } $sql = 'USE FEDERATION ROOT WITH RESET'; @@ -117,10 +112,10 @@ public function selectGlobal() /** * {@inheritDoc} */ - public function selectShard($distributionValue) + public function selectShard($distributionValue) : void { if ($this->conn->isTransactionActive()) { - throw ShardingException::activeTransaction(); + throw ActiveTransaction::new(); } $platform = $this->conn->getDatabasePlatform(); @@ -147,7 +142,7 @@ public function getCurrentDistributionValue() /** * {@inheritDoc} */ - public function getShards() + public function getShards() : array { $sql = 'SELECT member_id as id, distribution_name as distribution_key, @@ -163,11 +158,11 @@ public function getShards() /** * {@inheritDoc} */ - public function queryAll($sql, array $params = [], array $types = []) + public function queryAll(string $sql, array $params = [], array $types = []) : array { $shards = $this->getShards(); if (! $shards) { - throw new RuntimeException('No shards found for ' . $this->federationName); + throw new RuntimeException(sprintf('No shards found for "%s".', $this->federationName)); } $result = []; @@ -193,16 +188,12 @@ public function queryAll($sql, array $params = [], array $types = []) * Splits Federation at a given distribution value. * * @param mixed $splitDistributionValue - * - * @return void */ - public function splitFederation($splitDistributionValue) + public function splitFederation($splitDistributionValue) : void { - $type = Type::getType($this->distributionType); - $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' . 'SPLIT AT (' . $this->getDistributionKey() . ' = ' . - $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')'; + $this->conn->quote($splitDistributionValue) . ')'; $this->conn->exec($sql); } } diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php index a83b401c2cd..a14f26c2418 100644 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php +++ b/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php @@ -1,5 +1,7 @@ excludedTables = $excludedTables; $this->tenantColumnName = $tenantColumnName; @@ -65,7 +66,7 @@ public function __construct(array $excludedTables = [], $tenantColumnName = 'ten /** * {@inheritdoc} */ - public function acceptTable(Table $table) + public function acceptTable(Table $table) : void { if (in_array($table->getName(), $this->excludedTables)) { return; @@ -91,13 +92,9 @@ public function acceptTable(Table $table) } /** - * @param Table $table - * - * @return Index - * * @throws RuntimeException */ - private function getClusteredIndex($table) + private function getClusteredIndex(Table $table) : Index { foreach ($table->getIndexes() as $index) { if ($index->isPrimary() && ! $index->hasFlag('nonclustered')) { @@ -108,41 +105,41 @@ private function getClusteredIndex($table) return $index; } } - throw new RuntimeException('No clustered index found on table ' . $table->getName()); + throw new RuntimeException(sprintf('No clustered index found on table "%s".', $table->getName())); } /** * {@inheritdoc} */ - public function acceptSchema(Schema $schema) + public function acceptSchema(Schema $schema) : void { } /** * {@inheritdoc} */ - public function acceptColumn(Table $table, Column $column) + public function acceptColumn(Table $table, Column $column) : void { } /** * {@inheritdoc} */ - public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) : void { } /** * {@inheritdoc} */ - public function acceptIndex(Table $table, Index $index) + public function acceptIndex(Table $table, Index $index) : void { } /** * {@inheritdoc} */ - public function acceptSequence(Sequence $sequence) + public function acceptSequence(Sequence $sequence) : void { } } diff --git a/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php b/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php index 584e8155ae9..c6c2f3843f4 100644 --- a/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php +++ b/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php @@ -1,5 +1,7 @@ sql = $sql; $this->stmt = $conn->getWrappedConnection()->prepare($sql); @@ -81,31 +83,34 @@ public function __construct($sql, Connection $conn) * type and the value undergoes the conversion routines of the mapping type before * being bound. * - * @param string|int $name The name or position of the parameter. - * @param mixed $value The value of the parameter. - * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance. + * @param string|int $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position + * of the parameter. + * @param mixed $value The value to bind to the parameter. + * @param string|int|Type $type Either one of the constants defined in {@link \Doctrine\DBAL\ParameterType} + * or a DBAL mapping type name or instance. * - * @return bool TRUE on success, FALSE on failure. + * @throws DBALException + * @throws DriverException */ - public function bindValue($name, $value, $type = ParameterType::STRING) + public function bindValue($param, $value, $type = ParameterType::STRING) : void { - $this->params[$name] = $value; - $this->types[$name] = $type; - if ($type !== null) { - if (is_string($type)) { - $type = Type::getType($type); - } - if ($type instanceof Type) { - $value = $type->convertToDatabaseValue($value, $this->platform); - $bindingType = $type->getBindingType(); - } else { - $bindingType = $type; - } + $this->params[$param] = $value; + $this->types[$param] = $type; - return $this->stmt->bindValue($name, $value, $bindingType); + if (is_string($type)) { + $type = Type::getType($type); } - return $this->stmt->bindValue($name, $value); + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->platform); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type; + } + + $this->stmt->bindValue($param, $value, $bindingType); } /** @@ -113,117 +118,78 @@ public function bindValue($name, $value, $type = ParameterType::STRING) * * Binding a parameter by reference does not support DBAL mapping types. * - * @param string|int $name The name or position of the parameter. - * @param mixed $var The reference to the variable to bind. - * @param int $type The PDO binding type. - * @param int|null $length Must be specified when using an OUT bind - * so that PHP allocates enough memory to hold the returned value. + * @param string|int $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position + * of the parameter. + * @param mixed $variable The variable to bind to the parameter. + * @param int $type The PDO binding type. + * @param int|null $length Must be specified when using an OUT bind + * so that PHP allocates enough memory to hold the returned value. * - * @return bool TRUE on success, FALSE on failure. + * @throws DriverException */ - public function bindParam($name, &$var, $type = ParameterType::STRING, $length = null) + public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void { - $this->params[$name] = $var; - $this->types[$name] = $type; + $this->params[$param] = $variable; + $this->types[$param] = $type; - return $this->stmt->bindParam($name, $var, $type, $length); + $this->stmt->bindParam($param, $variable, $type, $length); } /** - * Executes the statement with the currently bound parameters. - * - * @param mixed[]|null $params - * - * @return bool TRUE on success, FALSE on failure. + * {@inheritDoc} * * @throws DBALException */ - public function execute($params = null) + public function execute(?array $params = null) : void { if (is_array($params)) { $this->params = $params; } $logger = $this->conn->getConfiguration()->getSQLLogger(); - if ($logger) { - $logger->startQuery($this->sql, $this->params, $this->types); - } + $logger->startQuery($this->sql, $this->params, $this->types); try { - $stmt = $this->stmt->execute($params); + $this->stmt->execute($params); } catch (Throwable $ex) { - if ($logger) { - $logger->stopQuery(); - } throw DBALException::driverExceptionDuringQuery( $this->conn->getDriver(), $ex, $this->sql, $this->conn->resolveParams($this->params, $this->types) ); - } - - if ($logger) { + } finally { $logger->stopQuery(); } + $this->params = []; $this->types = []; - - return $stmt; } /** - * Closes the cursor, freeing the database resources used by this statement. - * - * @return bool TRUE on success, FALSE on failure. + * {@inheritDoc} */ - public function closeCursor() + public function closeCursor() : void { - return $this->stmt->closeCursor(); + $this->stmt->closeCursor(); } /** * Returns the number of columns in the result set. - * - * @return int */ - public function columnCount() + public function columnCount() : int { return $this->stmt->columnCount(); } - /** - * Fetches the SQLSTATE associated with the last operation on the statement. - * - * @return string|int|bool - */ - public function errorCode() - { - return $this->stmt->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ - public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + public function setFetchMode(int $fetchMode, ...$args) : void { - if ($arg2 === null) { - return $this->stmt->setFetchMode($fetchMode); - } - - if ($arg3 === null) { - return $this->stmt->setFetchMode($fetchMode, $arg2); - } - - return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + $this->stmt->setFetchMode($fetchMode, ...$args); } /** @@ -239,27 +205,23 @@ public function getIterator() /** * {@inheritdoc} */ - public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + public function fetch(?int $fetchMode = null, ...$args) { - return $this->stmt->fetch($fetchMode); + return $this->stmt->fetch($fetchMode, ...$args); } /** * {@inheritdoc} */ - public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + public function fetchAll(?int $fetchMode = null, ...$args) : array { - if ($fetchArgument) { - return $this->stmt->fetchAll($fetchMode, $fetchArgument); - } - - return $this->stmt->fetchAll($fetchMode); + return $this->stmt->fetchAll($fetchMode, ...$args); } /** * {@inheritDoc} */ - public function fetchColumn($columnIndex = 0) + public function fetchColumn(int $columnIndex = 0) { return $this->stmt->fetchColumn($columnIndex); } @@ -269,17 +231,15 @@ public function fetchColumn($columnIndex = 0) * * @return int The number of affected rows. */ - public function rowCount() + public function rowCount() : int { return $this->stmt->rowCount(); } /** * Gets the wrapped driver statement. - * - * @return \Doctrine\DBAL\Driver\Statement */ - public function getWrappedStatement() + public function getWrappedStatement() : DriverStatement { return $this->stmt; } diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php deleted file mode 100644 index a45a60c6085..00000000000 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php +++ /dev/null @@ -1,138 +0,0 @@ -setName('dbal:import') - ->setDescription('Import SQL file(s) directly to Database.') - ->setDefinition([new InputArgument( - 'file', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'File path(s) of SQL to be executed.' - ), - ]) - ->setHelp(<<getHelper('db')->getConnection(); - - $fileNames = $input->getArgument('file'); - - if ($fileNames === null) { - return null; - } - - foreach ((array) $fileNames as $fileName) { - $filePath = realpath($fileName); - - // Phar compatibility. - if ($filePath === false) { - $filePath = $fileName; - } - - if (! file_exists($filePath)) { - throw new InvalidArgumentException( - sprintf("SQL file '%s' does not exist.", $filePath) - ); - } - - if (! is_readable($filePath)) { - throw new InvalidArgumentException( - sprintf("SQL file '%s' does not have read permissions.", $filePath) - ); - } - - $output->write(sprintf("Processing file '%s'... ", $filePath)); - $sql = @file_get_contents($filePath); - - if ($sql === false) { - throw new RuntimeException( - sprintf("Unable to read SQL file '%s': %s", $filePath, error_get_last()['message']) - ); - } - - if ($conn instanceof PDOConnection) { - // PDO Drivers - try { - $lines = 0; - - $stmt = $conn->prepare($sql); - assert($stmt instanceof PDOStatement); - - $stmt->execute(); - - do { - // Required due to "MySQL has gone away!" issue - $stmt->fetch(); - $stmt->closeCursor(); - - $lines++; - } while ($stmt->nextRowset()); - - $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); - } catch (PDOException $e) { - $output->write('error!' . PHP_EOL); - - throw new RuntimeException($e->getMessage(), $e->getCode(), $e); - } - } else { - // Non-PDO Drivers (ie. OCI8 driver) - $stmt = $conn->prepare($sql); - $rs = $stmt->execute(); - - if (! $rs) { - $error = $stmt->errorInfo(); - - $output->write('error!' . PHP_EOL); - - throw new RuntimeException($error[2], $error[0]); - } - - $output->writeln('OK!' . PHP_EOL); - - $stmt->closeCursor(); - } - } - - return null; - } -} diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php index 2e0c48a815b..9c5ba8c79cd 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -1,5 +1,7 @@ */ private $keywordListClasses = [ + 'db2' => DB2Keywords::class, 'mysql' => MySQLKeywords::class, 'mysql57' => MySQL57Keywords::class, 'mysql80' => MySQL80Keywords::class, - 'sqlserver' => SQLServerKeywords::class, - 'sqlserver2005' => SQLServer2005Keywords::class, - 'sqlserver2008' => SQLServer2008Keywords::class, - 'sqlserver2012' => SQLServer2012Keywords::class, - 'sqlite' => SQLiteKeywords::class, - 'pgsql' => PostgreSQLKeywords::class, - 'pgsql91' => PostgreSQL91Keywords::class, - 'pgsql92' => PostgreSQL92Keywords::class, 'oracle' => OracleKeywords::class, - 'db2' => DB2Keywords::class, + 'pgsql' => PostgreSQLKeywords::class, + 'pgsql94' => PostgreSQL94Keywords::class, + 'pgsql100' => PostgreSQL100Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, - 'sqlanywhere11' => SQLAnywhere11Keywords::class, - 'sqlanywhere12' => SQLAnywhere12Keywords::class, - 'sqlanywhere16' => SQLAnywhere16Keywords::class, + 'sqlite' => SQLiteKeywords::class, + 'sqlserver' => SQLServerKeywords::class, + 'sqlserver2012' => SQLServer2012Keywords::class, ]; /** * If you want to add or replace a keywords list use this command. - * - * @param string $name - * @param string $class - * - * @return void */ - public function setKeywordListClass($name, $class) + public function setKeywordListClass(string $name, string $class) : void { $this->keywordListClasses[$name] = $class; } @@ -69,7 +57,7 @@ public function setKeywordListClass($name, $class) /** * {@inheritdoc} */ - protected function configure() + protected function configure() : void { $this ->setName('dbal:reserved-words') @@ -101,17 +89,13 @@ protected function configure() * mysql57 * mysql80 * pgsql - * pgsql92 + * pgsql94 + * pgsql100 * sqlite * oracle * sqlserver - * sqlserver2005 - * sqlserver2008 * sqlserver2012 * sqlanywhere - * sqlanywhere11 - * sqlanywhere12 - * sqlanywhere16 * db2 (Not checked by default) EOT ); @@ -127,32 +111,17 @@ protected function execute(InputInterface $input, OutputInterface $output) $keywordLists = (array) $input->getOption('list'); if (! $keywordLists) { - $keywordLists = [ - 'mysql', - 'mysql57', - 'mysql80', - 'pgsql', - 'pgsql92', - 'sqlite', - 'oracle', - 'sqlserver', - 'sqlserver2005', - 'sqlserver2008', - 'sqlserver2012', - 'sqlanywhere', - 'sqlanywhere11', - 'sqlanywhere12', - 'sqlanywhere16', - ]; + $keywordLists = array_keys($this->keywordListClasses); } $keywords = []; foreach ($keywordLists as $keywordList) { if (! isset($this->keywordListClasses[$keywordList])) { - throw new InvalidArgumentException( - "There exists no keyword list with name '" . $keywordList . "'. " . - 'Known lists: ' . implode(', ', array_keys($this->keywordListClasses)) - ); + throw new InvalidArgumentException(sprintf( + 'There exists no keyword list with name "%s". Known lists: %s', + $keywordList, + implode(', ', array_keys($this->keywordListClasses)) + )); } $class = $this->keywordListClasses[$keywordList]; $keywords[] = new $class(); diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php index 8aeb0ea2fba..b6e27a1c972 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php @@ -1,5 +1,7 @@ setName('dbal:run-sql') @@ -50,7 +52,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $sql = $input->getArgument('sql'); if ($sql === null) { - throw new RuntimeException("Argument 'SQL' is required in order to execute this command correctly."); + throw new RuntimeException('Argument "sql" is required in order to execute this command correctly.'); } assert(is_string($sql)); @@ -58,7 +60,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $depth = $input->getOption('depth'); if (! is_numeric($depth)) { - throw new LogicException("Option 'depth' must contains an integer value"); + throw new LogicException('Option "depth" must contains an integer value.'); } if (stripos($sql, 'select') === 0 || $input->getOption('force-fetch')) { diff --git a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php index 520a9af80aa..a7a1e987e68 100644 --- a/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php +++ b/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php @@ -1,13 +1,14 @@ new ConnectionHelper($connection), @@ -32,13 +31,11 @@ public static function createHelperSet(Connection $connection) /** * Runs console with the given helperset. * - * @param Command[] $commands - * - * @return void + * @param array $commands */ - public static function run(HelperSet $helperSet, $commands = []) + public static function run(HelperSet $helperSet, array $commands = []) : void { - $cli = new Application('Doctrine Command Line Interface', Version::VERSION); + $cli = new Application('Doctrine Command Line Interface', Versions::getVersion('doctrine/dbal')); $cli->setCatchExceptions(true); $cli->setHelperSet($helperSet); @@ -49,14 +46,10 @@ public static function run(HelperSet $helperSet, $commands = []) $cli->run(); } - /** - * @return void - */ - public static function addCommands(Application $cli) + public static function addCommands(Application $cli) : void { $cli->addCommands([ new RunSqlCommand(), - new ImportCommand(), new ReservedWordsCommand(), ]); } @@ -64,7 +57,7 @@ public static function addCommands(Application $cli) /** * Prints the instructions to create a configuration file */ - public static function printCliConfigTemplate() + public static function printCliConfigTemplate() : void { echo <<<'HELP' You are missing a "cli-config.php" or "config/cli-config.php" file in your diff --git a/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php b/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php index b5497d068a0..971ee5629dc 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php +++ b/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php @@ -1,5 +1,7 @@ _connection; } diff --git a/lib/Doctrine/DBAL/Tools/Dumper.php b/lib/Doctrine/DBAL/Tools/Dumper.php index 3668efbe4d1..aae049972e2 100644 --- a/lib/Doctrine/DBAL/Tools/Dumper.php +++ b/lib/Doctrine/DBAL/Tools/Dumper.php @@ -1,5 +1,7 @@ getClobTypeDeclarationSQL($fieldDeclaration); } @@ -43,8 +46,8 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $value = is_resource($value) ? stream_get_contents($value) : $value; - set_error_handler(function (int $code, string $message) : void { - throw ConversionException::conversionFailedUnserialization($this->getName(), $message); + set_error_handler(function (int $code, string $message) use ($value) : void { + throw ValueNotConvertible::new($value, $this->getName(), $message); }); try { @@ -57,7 +60,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::ARRAY; } @@ -65,7 +68,7 @@ public function getName() /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/BigIntType.php b/lib/Doctrine/DBAL/Types/BigIntType.php index 69cd5341d84..b62d222fd98 100644 --- a/lib/Doctrine/DBAL/Types/BigIntType.php +++ b/lib/Doctrine/DBAL/Types/BigIntType.php @@ -1,5 +1,7 @@ getBigIntTypeDeclarationSQL($fieldDeclaration); } @@ -29,7 +31,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::STRING; } diff --git a/lib/Doctrine/DBAL/Types/BinaryType.php b/lib/Doctrine/DBAL/Types/BinaryType.php index d604b3bff69..da17c1408bc 100644 --- a/lib/Doctrine/DBAL/Types/BinaryType.php +++ b/lib/Doctrine/DBAL/Types/BinaryType.php @@ -1,15 +1,15 @@ getBinaryTypeDeclarationSQL($fieldDeclaration); } @@ -33,16 +33,12 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return null; } - if (is_string($value)) { - $fp = fopen('php://temp', 'rb+'); - assert(is_resource($fp)); - fwrite($fp, $value); - fseek($fp, 0); - $value = $fp; + if (is_resource($value)) { + $value = stream_get_contents($value); } - if (! is_resource($value)) { - throw ConversionException::conversionFailed($value, Types::BINARY); + if (! is_string($value)) { + throw ValueNotConvertible::new($value, self::BINARY); } return $value; @@ -51,7 +47,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::BINARY; } @@ -59,7 +55,7 @@ public function getName() /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::BINARY; } diff --git a/lib/Doctrine/DBAL/Types/BlobType.php b/lib/Doctrine/DBAL/Types/BlobType.php index e4bb22f08d8..af9a0d6ce3e 100644 --- a/lib/Doctrine/DBAL/Types/BlobType.php +++ b/lib/Doctrine/DBAL/Types/BlobType.php @@ -1,9 +1,12 @@ getBlobTypeDeclarationSQL($fieldDeclaration); } @@ -42,7 +45,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) } if (! is_resource($value)) { - throw ConversionException::conversionFailed($value, Types::BLOB); + throw ValueNotConvertible::new($value, self::BLOB); } return $value; @@ -51,7 +54,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::BLOB; } @@ -59,7 +62,7 @@ public function getName() /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::LARGE_OBJECT; } diff --git a/lib/Doctrine/DBAL/Types/BooleanType.php b/lib/Doctrine/DBAL/Types/BooleanType.php index bf9be9b19fe..9c1d7f8bdfb 100644 --- a/lib/Doctrine/DBAL/Types/BooleanType.php +++ b/lib/Doctrine/DBAL/Types/BooleanType.php @@ -1,5 +1,7 @@ getBooleanTypeDeclarationSQL($fieldDeclaration); } @@ -37,7 +39,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::BOOLEAN; } @@ -45,7 +47,7 @@ public function getName() /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::BOOLEAN; } diff --git a/lib/Doctrine/DBAL/Types/ConversionException.php b/lib/Doctrine/DBAL/Types/ConversionException.php index b9f8a82e7ec..aa588102cbd 100644 --- a/lib/Doctrine/DBAL/Types/ConversionException.php +++ b/lib/Doctrine/DBAL/Types/ConversionException.php @@ -1,109 +1,14 @@ 32 ? substr($value, 0, 20) . '...' : $value; - - return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType); - } - - /** - * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement - * about the expected format. - * - * @param string $value - * @param string $toType - * @param string $expectedFormat - * - * @return \Doctrine\DBAL\Types\ConversionException - */ - public static function conversionFailedFormat($value, $toType, $expectedFormat, ?Throwable $previous = null) - { - $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; - - return new self( - 'Could not convert database value "' . $value . '" to Doctrine Type ' . - $toType . '. Expected format: ' . $expectedFormat, - 0, - $previous - ); - } - - /** - * Thrown when the PHP value passed to the converter was not of the expected type. - * - * @param mixed $value - * @param string $toType - * @param string[] $possibleTypes - * - * @return \Doctrine\DBAL\Types\ConversionException - */ - public static function conversionFailedInvalidType($value, $toType, array $possibleTypes) - { - $actualType = is_object($value) ? get_class($value) : gettype($value); - - if (is_scalar($value)) { - return new self(sprintf( - "Could not convert PHP value '%s' of type '%s' to type '%s'. Expected one of the following types: %s", - $value, - $actualType, - $toType, - implode(', ', $possibleTypes) - )); - } - - return new self(sprintf( - "Could not convert PHP value of type '%s' to type '%s'. Expected one of the following types: %s", - $actualType, - $toType, - implode(', ', $possibleTypes) - )); - } - - public static function conversionFailedSerialization($value, $format, $error) - { - $actualType = is_object($value) ? get_class($value) : gettype($value); - - return new self(sprintf( - "Could not convert PHP type '%s' to '%s', as an '%s' error was triggered by the serialization", - $actualType, - $format, - $error - )); - } - - public static function conversionFailedUnserialization(string $format, string $error) : self - { - return new self(sprintf( - "Could not convert database value to '%s' as an error was triggered by the unserialization: '%s'", - $format, - $error - )); - } } diff --git a/lib/Doctrine/DBAL/Types/DateImmutableType.php b/lib/Doctrine/DBAL/Types/DateImmutableType.php index a4c5d266d92..7e747e27fc1 100644 --- a/lib/Doctrine/DBAL/Types/DateImmutableType.php +++ b/lib/Doctrine/DBAL/Types/DateImmutableType.php @@ -1,9 +1,13 @@ format($platform->getDateFormatString()); } - throw ConversionException::conversionFailedInvalidType( + throw InvalidType::new( $value, $this->getName(), ['null', DateTimeImmutable::class] @@ -50,7 +54,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getDateFormatString(), $value); if (! $dateTime) { - throw ConversionException::conversionFailedFormat( + throw InvalidFormat::new( $value, $this->getName(), $platform->getDateFormatString() @@ -63,7 +67,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/DateIntervalType.php b/lib/Doctrine/DBAL/Types/DateIntervalType.php index 96a446e8607..5ccdd570a06 100644 --- a/lib/Doctrine/DBAL/Types/DateIntervalType.php +++ b/lib/Doctrine/DBAL/Types/DateIntervalType.php @@ -1,9 +1,13 @@ getVarcharTypeDeclarationSQL($fieldDeclaration); + return $platform->getStringTypeDeclarationSQL($fieldDeclaration); } /** @@ -45,7 +49,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value->format(self::FORMAT); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); + throw InvalidType::new($value, $this->getName(), ['null', 'DateInterval']); } /** @@ -73,14 +77,14 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return $interval; } catch (Throwable $exception) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), self::FORMAT, $exception); + throw InvalidFormat::new($value, $this->getName(), self::FORMAT, $exception); } } /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php b/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php index 51960a8c344..d01023b1814 100644 --- a/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php +++ b/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php @@ -1,9 +1,13 @@ format($platform->getDateTimeFormatString()); } - throw ConversionException::conversionFailedInvalidType( + throw InvalidType::new( $value, $this->getName(), ['null', DateTimeImmutable::class] @@ -55,7 +59,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) } if (! $dateTime) { - throw ConversionException::conversionFailedFormat( + throw InvalidFormat::new( $value, $this->getName(), $platform->getDateTimeFormatString() @@ -68,7 +72,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/DateTimeType.php b/lib/Doctrine/DBAL/Types/DateTimeType.php index 65071a6b188..1fc8866efde 100644 --- a/lib/Doctrine/DBAL/Types/DateTimeType.php +++ b/lib/Doctrine/DBAL/Types/DateTimeType.php @@ -1,10 +1,14 @@ getDateTimeTypeDeclarationSQL($fieldDeclaration); } @@ -41,7 +45,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value->format($platform->getDateTimeFormatString()); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + throw InvalidType::new($value, $this->getName(), ['null', 'DateTime']); } /** @@ -60,7 +64,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) } if (! $val) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); + throw InvalidFormat::new($value, $this->getName(), $platform->getDateTimeFormatString()); } return $val; diff --git a/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php b/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php index b888624796e..e12bcf60cc7 100644 --- a/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php +++ b/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php @@ -1,9 +1,13 @@ format($platform->getDateTimeTzFormatString()); } - throw ConversionException::conversionFailedInvalidType( + throw InvalidType::new( $value, $this->getName(), ['null', DateTimeImmutable::class] @@ -50,7 +54,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $dateTime = DateTimeImmutable::createFromFormat($platform->getDateTimeTzFormatString(), $value); if (! $dateTime) { - throw ConversionException::conversionFailedFormat( + throw InvalidFormat::new( $value, $this->getName(), $platform->getDateTimeTzFormatString() @@ -63,7 +67,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/DateTimeTzType.php b/lib/Doctrine/DBAL/Types/DateTimeTzType.php index 6240da8926c..001eb83a98e 100644 --- a/lib/Doctrine/DBAL/Types/DateTimeTzType.php +++ b/lib/Doctrine/DBAL/Types/DateTimeTzType.php @@ -1,10 +1,14 @@ getDateTimeTzTypeDeclarationSQL($fieldDeclaration); } @@ -53,7 +57,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value->format($platform->getDateTimeTzFormatString()); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + throw InvalidType::new($value, $this->getName(), ['null', 'DateTime']); } /** @@ -67,7 +71,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $val = DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value); if (! $val) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeTzFormatString()); + throw InvalidFormat::new($value, $this->getName(), $platform->getDateTimeTzFormatString()); } return $val; diff --git a/lib/Doctrine/DBAL/Types/DateType.php b/lib/Doctrine/DBAL/Types/DateType.php index 15d9362f288..94272df00ac 100644 --- a/lib/Doctrine/DBAL/Types/DateType.php +++ b/lib/Doctrine/DBAL/Types/DateType.php @@ -1,10 +1,14 @@ getDateTypeDeclarationSQL($fieldDeclaration); } @@ -40,7 +44,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value->format($platform->getDateFormatString()); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + throw InvalidType::new($value, $this->getName(), ['null', 'DateTime']); } /** @@ -54,7 +58,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $val = DateTime::createFromFormat('!' . $platform->getDateFormatString(), $value); if (! $val) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateFormatString()); + throw InvalidFormat::new($value, $this->getName(), $platform->getDateFormatString()); } return $val; diff --git a/lib/Doctrine/DBAL/Types/DecimalType.php b/lib/Doctrine/DBAL/Types/DecimalType.php index b2d37f00b3e..72eb2438624 100644 --- a/lib/Doctrine/DBAL/Types/DecimalType.php +++ b/lib/Doctrine/DBAL/Types/DecimalType.php @@ -1,5 +1,7 @@ getDecimalTypeDeclarationSQL($fieldDeclaration); } diff --git a/lib/Doctrine/DBAL/Types/Exception/InvalidFormat.php b/lib/Doctrine/DBAL/Types/Exception/InvalidFormat.php new file mode 100644 index 00000000000..8eb4b86417c --- /dev/null +++ b/lib/Doctrine/DBAL/Types/Exception/InvalidFormat.php @@ -0,0 +1,36 @@ + 32 ? substr($value, 0, 20) . '...' : $value, + $toType, + $expectedFormat ?? '' + ), + 0, + $previous + ); + } +} diff --git a/lib/Doctrine/DBAL/Types/Exception/InvalidType.php b/lib/Doctrine/DBAL/Types/Exception/InvalidType.php new file mode 100644 index 00000000000..2ee2439619a --- /dev/null +++ b/lib/Doctrine/DBAL/Types/Exception/InvalidType.php @@ -0,0 +1,52 @@ + 32 ? substr($value, 0, 20) . '...' : $value, + $toType + ) + ); + } +} diff --git a/lib/Doctrine/DBAL/Types/FloatType.php b/lib/Doctrine/DBAL/Types/FloatType.php index 4988d7253dc..a27f9085116 100644 --- a/lib/Doctrine/DBAL/Types/FloatType.php +++ b/lib/Doctrine/DBAL/Types/FloatType.php @@ -1,5 +1,7 @@ getFloatDeclarationSQL($fieldDeclaration); } diff --git a/lib/Doctrine/DBAL/Types/GuidType.php b/lib/Doctrine/DBAL/Types/GuidType.php index dd4516505ec..b507e1ed33d 100644 --- a/lib/Doctrine/DBAL/Types/GuidType.php +++ b/lib/Doctrine/DBAL/Types/GuidType.php @@ -1,5 +1,7 @@ getGuidTypeDeclarationSQL($fieldDeclaration); } @@ -20,7 +22,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::GUID; } @@ -28,7 +30,7 @@ public function getName() /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return ! $platform->hasNativeGuidType(); } diff --git a/lib/Doctrine/DBAL/Types/IntegerType.php b/lib/Doctrine/DBAL/Types/IntegerType.php index d7ab8fd80f2..9823791fcef 100644 --- a/lib/Doctrine/DBAL/Types/IntegerType.php +++ b/lib/Doctrine/DBAL/Types/IntegerType.php @@ -1,5 +1,7 @@ getIntegerTypeDeclarationSQL($fieldDeclaration); } @@ -37,7 +39,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::INTEGER; } diff --git a/lib/Doctrine/DBAL/Types/JsonArrayType.php b/lib/Doctrine/DBAL/Types/JsonArrayType.php deleted file mode 100644 index bc468fba0f3..00000000000 --- a/lib/Doctrine/DBAL/Types/JsonArrayType.php +++ /dev/null @@ -1,46 +0,0 @@ -getJsonTypeDeclarationSQL($fieldDeclaration); } @@ -36,7 +40,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) $encoded = json_encode($value); if (json_last_error() !== JSON_ERROR_NONE) { - throw ConversionException::conversionFailedSerialization($value, 'json', json_last_error_msg()); + throw SerializationFailed::new($value, 'json', json_last_error_msg()); } return $encoded; @@ -58,7 +62,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $val = json_decode($value, true); if (json_last_error() !== JSON_ERROR_NONE) { - throw ConversionException::conversionFailed($value, $this->getName()); + throw ValueNotConvertible::new($value, $this->getName()); } return $val; @@ -67,7 +71,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::JSON; } @@ -75,7 +79,7 @@ public function getName() /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return ! $platform->hasNativeJsonType(); } diff --git a/lib/Doctrine/DBAL/Types/ObjectType.php b/lib/Doctrine/DBAL/Types/ObjectType.php index 32f5f4efd02..bf8923dca0c 100644 --- a/lib/Doctrine/DBAL/Types/ObjectType.php +++ b/lib/Doctrine/DBAL/Types/ObjectType.php @@ -1,8 +1,11 @@ getClobTypeDeclarationSQL($fieldDeclaration); } @@ -42,8 +45,8 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $value = is_resource($value) ? stream_get_contents($value) : $value; - set_error_handler(function (int $code, string $message) : void { - throw ConversionException::conversionFailedUnserialization($this->getName(), $message); + set_error_handler(function (int $code, string $message) use ($value) : void { + throw ValueNotConvertible::new($value, $this->getName(), $message); }); try { @@ -56,7 +59,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::OBJECT; } @@ -64,7 +67,7 @@ public function getName() /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php b/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php index 45658505330..501bc37a7be 100644 --- a/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php +++ b/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php @@ -1,5 +1,7 @@ getClobTypeDeclarationSQL($fieldDeclaration); } @@ -52,7 +54,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::SIMPLE_ARRAY; } @@ -60,7 +62,7 @@ public function getName() /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/SmallIntType.php b/lib/Doctrine/DBAL/Types/SmallIntType.php index 5fa3cb74bbc..7e15d840c93 100644 --- a/lib/Doctrine/DBAL/Types/SmallIntType.php +++ b/lib/Doctrine/DBAL/Types/SmallIntType.php @@ -1,5 +1,7 @@ getSmallIntTypeDeclarationSQL($fieldDeclaration); } @@ -37,7 +39,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::INTEGER; } diff --git a/lib/Doctrine/DBAL/Types/StringType.php b/lib/Doctrine/DBAL/Types/StringType.php index e0d1a552f5d..104ad03f5e3 100644 --- a/lib/Doctrine/DBAL/Types/StringType.php +++ b/lib/Doctrine/DBAL/Types/StringType.php @@ -1,5 +1,7 @@ getVarcharTypeDeclarationSQL($fieldDeclaration); - } - - /** - * {@inheritdoc} - */ - public function getDefaultLength(AbstractPlatform $platform) + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string { - return $platform->getVarcharDefaultLength(); + return $platform->getStringTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::STRING; } diff --git a/lib/Doctrine/DBAL/Types/TextType.php b/lib/Doctrine/DBAL/Types/TextType.php index 76dd7c48cf0..43740cd011c 100644 --- a/lib/Doctrine/DBAL/Types/TextType.php +++ b/lib/Doctrine/DBAL/Types/TextType.php @@ -1,5 +1,7 @@ getClobTypeDeclarationSQL($fieldDeclaration); } @@ -30,7 +32,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function getName() + public function getName() : string { return Types::TEXT; } diff --git a/lib/Doctrine/DBAL/Types/TimeImmutableType.php b/lib/Doctrine/DBAL/Types/TimeImmutableType.php index cc437695564..1914d374187 100644 --- a/lib/Doctrine/DBAL/Types/TimeImmutableType.php +++ b/lib/Doctrine/DBAL/Types/TimeImmutableType.php @@ -1,9 +1,13 @@ format($platform->getTimeFormatString()); } - throw ConversionException::conversionFailedInvalidType( + throw InvalidType::new( $value, $this->getName(), ['null', DateTimeImmutable::class] @@ -50,7 +54,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getTimeFormatString(), $value); if (! $dateTime) { - throw ConversionException::conversionFailedFormat( + throw InvalidFormat::new( $value, $this->getName(), $platform->getTimeFormatString() @@ -63,7 +67,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/TimeType.php b/lib/Doctrine/DBAL/Types/TimeType.php index 1eeb2c01d1f..6d27c0100c3 100644 --- a/lib/Doctrine/DBAL/Types/TimeType.php +++ b/lib/Doctrine/DBAL/Types/TimeType.php @@ -1,10 +1,14 @@ getTimeTypeDeclarationSQL($fieldDeclaration); } @@ -40,7 +44,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) return $value->format($platform->getTimeFormatString()); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + throw InvalidType::new($value, $this->getName(), ['null', 'DateTime']); } /** @@ -54,7 +58,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $val = DateTime::createFromFormat('!' . $platform->getTimeFormatString(), $value); if (! $val) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getTimeFormatString()); + throw InvalidFormat::new($value, $this->getName(), $platform->getTimeFormatString()); } return $val; diff --git a/lib/Doctrine/DBAL/Types/Type.php b/lib/Doctrine/DBAL/Types/Type.php index ac7ab7bec13..d476bf56ce3 100644 --- a/lib/Doctrine/DBAL/Types/Type.php +++ b/lib/Doctrine/DBAL/Types/Type.php @@ -1,5 +1,7 @@ GuidType::class, Types::INTEGER => IntegerType::class, Types::JSON => JsonType::class, - Types::JSON_ARRAY => JsonArrayType::class, Types::OBJECT => ObjectType::class, Types::SIMPLE_ARRAY => SimpleArrayType::class, Types::SMALLINT => SmallIntType::class, @@ -162,36 +157,22 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return $value; } - /** - * Gets the default length of this type. - * - * @deprecated Rely on information provided by the platform instead. - * - * @return int|null - */ - public function getDefaultLength(AbstractPlatform $platform) - { - return null; - } - /** * Gets the SQL declaration snippet for a field of this type. * - * @param mixed[] $fieldDeclaration The field declaration. - * @param AbstractPlatform $platform The currently used database platform. + * @param array $fieldDeclaration The field declaration. + * @param AbstractPlatform $platform The currently used database platform. * - * @return string + * @throws DBALException */ - abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform); + abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string; /** * Gets the name of this type. * - * @return string - * * @todo Needed? */ - abstract public function getName(); + abstract public function getName() : string; /** * @internal This method is only to be used within DBAL for forward compatibility purposes. Do not use directly. @@ -222,11 +203,9 @@ private static function createTypeRegistry() : TypeRegistry * * @param string $name The name of the type (as returned by getName()). * - * @return \Doctrine\DBAL\Types\Type - * * @throws DBALException */ - public static function getType($name) + public static function getType(string $name) : self { return self::getTypeRegistry()->get($name); } @@ -237,11 +216,9 @@ public static function getType($name) * @param string $name The name of the type. This should correspond to what getName() returns. * @param string $className The class name of the custom type. * - * @return void - * * @throws DBALException */ - public static function addType($name, $className) + public static function addType(string $name, string $className) : void { self::getTypeRegistry()->register($name, new $className()); } @@ -253,7 +230,7 @@ public static function addType($name, $className) * * @return bool TRUE if type is supported; FALSE otherwise. */ - public static function hasType($name) + public static function hasType(string $name) : bool { return self::getTypeRegistry()->has($name); } @@ -261,14 +238,9 @@ public static function hasType($name) /** * Overrides an already defined type to use a different implementation. * - * @param string $name - * @param string $className - * - * @return void - * * @throws DBALException */ - public static function overrideType($name, $className) + public static function overrideType(string $name, string $className) : void { self::getTypeRegistry()->override($name, new $className()); } @@ -278,10 +250,8 @@ public static function overrideType($name, $className) * can be used when binding parameters to prepared statements. * * This method should return one of the {@link \Doctrine\DBAL\ParameterType} constants. - * - * @return int */ - public function getBindingType() + public function getBindingType() : int { return ParameterType::STRING; } @@ -290,9 +260,9 @@ public function getBindingType() * Gets the types array map which holds all registered types and the corresponding * type class * - * @return string[] + * @return array */ - public static function getTypesMap() + public static function getTypesMap() : array { return array_map( static function (Type $type) : string { @@ -302,23 +272,6 @@ static function (Type $type) : string { ); } - /** - * @deprecated Relying on string representation is discouraged and will be removed in DBAL 3.0. - * - * @return string - */ - public function __toString() - { - $type = static::class; - $position = strrpos($type, '\\'); - - if ($position !== false) { - $type = substr($type, $position); - } - - return str_replace('Type', '', $type); - } - /** * Does working with this column require SQL conversion functions? * @@ -326,35 +279,24 @@ public function __toString() * Usage of {@link convertToDatabaseValueSQL} and * {@link convertToPHPValueSQL} works for any type and mostly * does nothing. This method can additionally be used for optimization purposes. - * - * @return bool */ - public function canRequireSQLConversion() + public function canRequireSQLConversion() : bool { return false; } /** * Modifies the SQL expression (identifier, parameter) to convert to a database value. - * - * @param string $sqlExpr - * - * @return string */ - public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + public function convertToDatabaseValueSQL(string $sqlExpr, AbstractPlatform $platform) : string { return $sqlExpr; } /** * Modifies the SQL expression (identifier, parameter) to convert to a PHP value. - * - * @param string $sqlExpr - * @param AbstractPlatform $platform - * - * @return string */ - public function convertToPHPValueSQL($sqlExpr, $platform) + public function convertToPHPValueSQL(string $sqlExpr, AbstractPlatform $platform) : string { return $sqlExpr; } @@ -362,9 +304,9 @@ public function convertToPHPValueSQL($sqlExpr, $platform) /** * Gets an array of database types that map to this Doctrine type. * - * @return string[] + * @return array */ - public function getMappedDatabaseTypes(AbstractPlatform $platform) + public function getMappedDatabaseTypes(AbstractPlatform $platform) : array { return []; } @@ -374,10 +316,8 @@ public function getMappedDatabaseTypes(AbstractPlatform $platform) * reverse schema engineering can't tell them apart. You need to mark * one of those types as commented, which will have Doctrine use an SQL * comment to typehint the actual Doctrine Type. - * - * @return bool */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return false; } diff --git a/lib/Doctrine/DBAL/Types/TypeRegistry.php b/lib/Doctrine/DBAL/Types/TypeRegistry.php index 7e8093cf749..c353620b942 100644 --- a/lib/Doctrine/DBAL/Types/TypeRegistry.php +++ b/lib/Doctrine/DBAL/Types/TypeRegistry.php @@ -5,6 +5,11 @@ namespace Doctrine\DBAL\Types; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Types\Exception\TypeAlreadyRegistered; +use Doctrine\DBAL\Types\Exception\TypeNotFound; +use Doctrine\DBAL\Types\Exception\TypeNotRegistered; +use Doctrine\DBAL\Types\Exception\TypesAlreadyExists; +use Doctrine\DBAL\Types\Exception\UnknownColumnType; use function array_search; use function in_array; @@ -16,7 +21,11 @@ */ final class TypeRegistry { - /** @var array Map of type names and their corresponding flyweight objects. */ + /** + * Map of type names and their corresponding flyweight objects. + * + * @var array + */ private $instances = []; /** @@ -27,7 +36,7 @@ final class TypeRegistry public function get(string $name) : Type { if (! isset($this->instances[$name])) { - throw DBALException::unknownColumnType($name); + throw UnknownColumnType::new($name); } return $this->instances[$name]; @@ -43,7 +52,7 @@ public function lookupName(Type $type) : string $name = $this->findTypeName($type); if ($name === null) { - throw DBALException::typeNotRegistered($type); + throw TypeNotRegistered::new($type); } return $name; @@ -65,11 +74,11 @@ public function has(string $name) : bool public function register(string $name, Type $type) : void { if (isset($this->instances[$name])) { - throw DBALException::typeExists($name); + throw TypesAlreadyExists::new($name); } if ($this->findTypeName($type) !== null) { - throw DBALException::typeAlreadyRegistered($type); + throw TypeAlreadyRegistered::new($type); } $this->instances[$name] = $type; @@ -83,11 +92,11 @@ public function register(string $name, Type $type) : void public function override(string $name, Type $type) : void { if (! isset($this->instances[$name])) { - throw DBALException::typeNotFound($name); + throw TypeNotFound::new($name); } if (! in_array($this->findTypeName($type), [$name, null], true)) { - throw DBALException::typeAlreadyRegistered($type); + throw TypeAlreadyRegistered::new($type); } $this->instances[$name] = $type; diff --git a/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.php b/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.php index 38beb3badf6..1bf15898c9c 100644 --- a/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.php +++ b/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.php @@ -1,9 +1,13 @@ format($platform->getDateTimeFormatString()); } - throw ConversionException::conversionFailedInvalidType( + throw InvalidType::new( $value, $this->getName(), ['null', DateTimeImmutable::class] @@ -51,7 +55,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $dateTime = date_create_immutable($value); if (! $dateTime) { - throw ConversionException::conversionFailed($value, $this->getName()); + throw ValueNotConvertible::new($value, $this->getName()); } return $dateTime; @@ -60,7 +64,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) /** * {@inheritdoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/lib/Doctrine/DBAL/Types/VarDateTimeType.php b/lib/Doctrine/DBAL/Types/VarDateTimeType.php index 1d9dbd3a6c6..e3ad78126fe 100644 --- a/lib/Doctrine/DBAL/Types/VarDateTimeType.php +++ b/lib/Doctrine/DBAL/Types/VarDateTimeType.php @@ -1,9 +1,12 @@ getName()); + throw ValueNotConvertible::new($value, $this->getName()); } return $val; diff --git a/lib/Doctrine/DBAL/Version.php b/lib/Doctrine/DBAL/Version.php deleted file mode 100644 index 93be3a1dfba..00000000000 --- a/lib/Doctrine/DBAL/Version.php +++ /dev/null @@ -1,33 +0,0 @@ -tests - - - */lib/* - - - - */lib/* - - */tests/* @@ -72,4 +63,10 @@ lib/Doctrine/DBAL/Schema/Comparator.php + + + + lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7aca228c393..2f3ce701984 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,7 @@ parameters: level: 7 paths: - %currentWorkingDirectory%/lib + - %currentWorkingDirectory%/tests autoload_files: - %currentWorkingDirectory%/tests/phpstan-polyfill.php reportUnmatchedIgnoredErrors: false @@ -26,10 +27,9 @@ parameters: - '~^Method Doctrine\\DBAL\\Schema\\(Oracle|PostgreSql|SQLServer)SchemaManager::_getPortableTableDefinition\(\) should return array but returns string\.\z~' - '~^Method Doctrine\\DBAL\\Platforms\\(|SQLAnywhere|Sqlite)Platform::_getTransactionIsolationLevelSQL\(\) should return string but returns int\.\z~' - '~^Method Doctrine\\DBAL\\Driver\\OCI8\\OCI8Connection::lastInsertId\(\) should return string but returns (int|false)\.\z~' - - '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~' # http://php.net/manual/en/pdo.sqlitecreatefunction.php - - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOConnection::sqliteCreateFunction\(\)\.\z~' + - '~^Call to an undefined method PDO::sqliteCreateFunction\(\)\.\z~' # https://github.com/JetBrains/phpstorm-stubs/pull/488 - '~^Parameter #1 \$byteCount of function SQLSRV_SQLTYPE_VARBINARY expects int, string given\.\z~' @@ -59,3 +59,34 @@ parameters: # weird class name, doesn't exist in stubs either - '~unknown class OCI-(Lob|Collection)~' + + # https://github.com/doctrine/dbal/issues/3237 + - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOStatement::nextRowset\(\)~' + + # https://github.com/phpstan/phpstan/pull/1886 + - + message: '~^Strict comparison using === between string|false and null will always evaluate to false\.~' + path: %currentWorkingDirectory%/lib/Doctrine/DBAL/Driver/PDOStatement.php + + # impossible inference for covariance + - '~^Property Doctrine\\Tests\\DBAL\\Types\\\S+Test::\$type \(Doctrine\\DBAL\\Types\\\S+Type\) does not accept Doctrine\\DBAL\\Types\\Type\.\z~' + - '~^Property Doctrine\\Tests\\DBAL\\Tools\\Console\\RunSqlCommandTest::\$command \(Doctrine\\DBAL\\Tools\\Console\\Command\\RunSqlCommand\) does not accept Symfony\\Component\\Console\\Command\\Command\.\z~' + + # https://github.com/phpstan/phpstan-phpunit/pull/28 + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/ConnectionTest.php + - + message: '~Call to method expects\(\) on an unknown class \S+~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php + + # https://github.com/doctrine/dbal/pull/3582/files#r290847062 + - + message: '~Parameter #3 \$type of method Doctrine\\DBAL\\Driver\\Statement::bindValue\(\) expects int, string given\.~' + path: %currentWorkingDirectory%/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/tests/Doctrine/Tests/DBAL/Cache/ArrayStatementTest.php b/tests/Doctrine/Tests/DBAL/Cache/ArrayStatementTest.php new file mode 100644 index 00000000000..a8322faa109 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Cache/ArrayStatementTest.php @@ -0,0 +1,147 @@ +> */ + private $users = [ + [ + 'username' => 'jwage', + 'active' => true, + ], + [ + 'username' => 'romanb', + 'active' => false, + ], + ]; + + public function testCloseCursor() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame(2, $statement->rowCount()); + + $statement->closeCursor(); + + self::assertSame(0, $statement->rowCount()); + } + + public function testColumnCount() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame(2, $statement->columnCount()); + } + + public function testRowCount() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame(2, $statement->rowCount()); + } + + public function testSetFetchMode() : void + { + $statement = $this->createTestArrayStatement(); + + $statement->setFetchMode(FetchMode::ASSOCIATIVE); + + self::assertSame($this->users[0], $statement->fetch()); + } + + public function testSetFetchModeThrowsInvalidArgumentException() : void + { + $statement = $this->createTestArrayStatement(); + + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage('Caching layer does not support 2nd/3rd argument to setFetchMode().'); + + $statement->setFetchMode(FetchMode::ASSOCIATIVE, 'arg1', 'arg2'); + } + + public function testGetIterator() : void + { + $statement = $this->createTestArrayStatement(); + $statement->setFetchMode(FetchMode::ASSOCIATIVE); + + self::assertSame($this->users, iterator_to_array($statement->getIterator())); + } + + public function testFetchModeAssociative() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame($this->users[0], $statement->fetch(FetchMode::ASSOCIATIVE)); + } + + public function testFetchModeNumeric() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame(array_values($this->users[0]), $statement->fetch(FetchMode::NUMERIC)); + } + + public function testFetchModeMixed() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame([ + 'username' => 'jwage', + 'active' => true, + 0 => 'jwage', + 1 => true, + ], $statement->fetch(FetchMode::MIXED)); + } + + public function testFetchModeColumn() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame('jwage', $statement->fetch(FetchMode::COLUMN)); + } + + public function testFetchThrowsInvalidArgumentException() : void + { + $statement = $this->createTestArrayStatement(); + + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage('Invalid fetch mode given for fetching result, 9999 given.'); + + $statement->fetch(9999); + } + + public function testFetchAll() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame($this->users, $statement->fetchAll(FetchMode::ASSOCIATIVE)); + } + + public function testFetchColumn() : void + { + $statement = $this->createTestArrayStatement(); + + self::assertSame('jwage', $statement->fetchColumn(0)); + self::assertSame('romanb', $statement->fetchColumn(0)); + + $statement = $this->createTestArrayStatement(); + + self::assertTrue($statement->fetchColumn(1)); + self::assertFalse($statement->fetchColumn(1)); + } + + private function createTestArrayStatement() : ArrayStatement + { + return new ArrayStatement($this->users); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php index 217b27d1f2f..e75ea147d56 100644 --- a/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php +++ b/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php @@ -1,5 +1,7 @@ config->setAutoCommit(false); self::assertFalse($this->config->getAutoCommit()); - - $this->config->setAutoCommit(0); - - self::assertFalse($this->config->getAutoCommit()); } } diff --git a/tests/Doctrine/Tests/DBAL/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/ConnectionTest.php index dfd89f80dd6..2632d7568ee 100644 --- a/tests/Doctrine/Tests/DBAL/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/ConnectionTest.php @@ -1,5 +1,7 @@ */ protected $params = [ 'driver' => 'pdo_mysql', 'host' => 'localhost', 'user' => 'root', 'password' => 'password', - 'port' => '1234', + 'port' => 1234, ]; protected function setUp() : void @@ -113,26 +114,6 @@ public function testGetConfiguration() : void self::assertInstanceOf(Configuration::class, $config); } - public function testGetHost() : void - { - self::assertEquals('localhost', $this->connection->getHost()); - } - - public function testGetPort() : void - { - self::assertEquals('1234', $this->connection->getPort()); - } - - public function testGetUsername() : void - { - self::assertEquals('root', $this->connection->getUsername()); - } - - public function testGetPassword() : void - { - self::assertEquals('password', $this->connection->getPassword()); - } - public function testGetDriver() : void { self::assertInstanceOf(\Doctrine\DBAL\Driver\PDOMySql\Driver::class, $this->connection->getDriver()); @@ -188,7 +169,7 @@ public function testEventManagerPassedToPlatform() : void public function testDriverExceptionIsWrapped(string $method) : void { $this->expectException(DBALException::class); - $this->expectExceptionMessage("An exception occurred while executing 'MUUHAAAAHAAAA':\n\nSQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\""); + $this->expectExceptionMessage("An exception occurred while executing \"MUUHAAAAHAAAA\":\n\nSQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\""); $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', @@ -251,8 +232,6 @@ public function testSetAutoCommit() : void { $this->connection->setAutoCommit(false); self::assertFalse($this->connection->isAutoCommit()); - $this->connection->setAutoCommit(0); - self::assertFalse($this->connection->isAutoCommit()); } /** @@ -656,82 +635,28 @@ public function testFetchAll() : void self::assertSame($result, $conn->fetchAll($statement, $params, $types)); } - public function testConnectionDoesNotMaintainTwoReferencesToExternalPDO() : void - { - $params['pdo'] = new stdClass(); - - $driverMock = $this->createMock(Driver::class); - - $conn = new Connection($params, $driverMock); - - self::assertArrayNotHasKey('pdo', $conn->getParams(), 'Connection is maintaining additional reference to the PDO connection'); - } - - public function testPassingExternalPDOMeansConnectionIsConnected() : void - { - $params['pdo'] = new stdClass(); - - $driverMock = $this->createMock(Driver::class); - - $conn = new Connection($params, $driverMock); - - self::assertTrue($conn->isConnected(), 'Connection is not connected after passing external PDO'); - } - public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void { /** @var Driver $driver */ - $driver = $this->createMock(Driver::class); - $pdoMock = $this->createMock(\Doctrine\DBAL\Driver\Connection::class); - - // should never execute queries with invalid arguments - $pdoMock->expects($this->never())->method('exec'); - $pdoMock->expects($this->never())->method('prepare'); - - $conn = new Connection(['pdo' => $pdoMock], $driver); + $driver = $this->createMock(Driver::class); + $conn = new Connection([], $driver); $this->expectException(InvalidArgumentException::class); $conn->delete('kittens', []); } - /** - * @return array> - */ - public static function dataCallConnectOnce() : iterable + public function testCallConnectOnce() : void { - return [ - ['delete', ['tbl', ['id' => 12345]]], - ['insert', ['tbl', ['data' => 'foo']]], - ['update', ['tbl', ['data' => 'bar'], ['id' => 12345]]], - ['prepare', ['select * from dual']], - ['executeUpdate', ['insert into tbl (id) values (?)'], [123]], - ]; - } - - /** - * @param array $params - * - * @dataProvider dataCallConnectOnce - */ - public function testCallConnectOnce(string $method, array $params) : void - { - $driverMock = $this->createMock(Driver::class); - $pdoMock = $this->createMock(Connection::class); - $platformMock = $this->createMock(AbstractPlatform::class); - $stmtMock = $this->createMock(Statement::class); - - $pdoMock->expects($this->any()) - ->method('prepare') - ->will($this->returnValue($stmtMock)); - - $conn = $this->getMockBuilder(Connection::class) - ->setConstructorArgs([['pdo' => $pdoMock, 'platform' => $platformMock], $driverMock]) - ->setMethods(['connect']) - ->getMock(); + /** @var Driver|MockObject $driver */ + $driver = $this->createMock(Driver::class); + $driver->expects($this->once()) + ->method('connect'); - $conn->expects($this->once())->method('connect'); + $platform = $this->createMock(AbstractPlatform::class); - call_user_func_array([$conn, $method], $params); + $conn = new Connection(['platform' => $platform], $driver); + $conn->connect(); + $conn->connect(); } /** @@ -742,8 +667,8 @@ public function testPlatformDetectionIsTriggerOnlyOnceOnRetrievingPlatform() : v /** @var Driver|VersionAwarePlatformDriver|MockObject $driverMock */ $driverMock = $this->createMock([Driver::class, VersionAwarePlatformDriver::class]); - /** @var ServerInfoAwareConnection|MockObject $driverConnectionMock */ - $driverConnectionMock = $this->createMock(ServerInfoAwareConnection::class); + /** @var DriverConnection|ServerInfoAwareConnection|MockObject $driverConnectionMock */ + $driverConnectionMock = $this->createMock([DriverConnection::class, ServerInfoAwareConnection::class]); /** @var AbstractPlatform|MockObject $platformMock */ $platformMock = $this->getMockForAbstractClass(AbstractPlatform::class); diff --git a/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php b/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php index 7db5921ba79..4745b392a52 100644 --- a/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php @@ -1,11 +1,15 @@ getMessage() @@ -65,10 +69,10 @@ public function testDriverRequiredWithUrl() : void */ public function testInvalidPlatformTypeObject() : void { - $exception = DBALException::invalidPlatformType(new stdClass()); + $exception = InvalidPlatformType::new(new stdClass()); self::assertSame( - "Option 'platform' must be a subtype of 'Doctrine\DBAL\Platforms\AbstractPlatform', instance of 'stdClass' given", + 'Option "platform" must be a subtype of Doctrine\DBAL\Platforms\AbstractPlatform, instance of stdClass given.', $exception->getMessage() ); } @@ -78,10 +82,10 @@ public function testInvalidPlatformTypeObject() : void */ public function testInvalidPlatformTypeScalar() : void { - $exception = DBALException::invalidPlatformType('some string'); + $exception = InvalidPlatformType::new('some string'); self::assertSame( - "Option 'platform' must be an object and subtype of 'Doctrine\DBAL\Platforms\AbstractPlatform'. Got 'string'", + 'Option "platform" must be an object and subtype of Doctrine\DBAL\Platforms\AbstractPlatform. Got string.', $exception->getMessage() ); } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractDB2DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractDB2DriverTest.php index 7038f5f8340..e9750ad9adf 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractDB2DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractDB2DriverTest.php @@ -1,5 +1,7 @@ driver instanceof ExceptionConverterDriver) { $this->markTestSkipped('This test is only intended for exception converter drivers.'); @@ -81,10 +81,8 @@ public function testConvertsException($errorCode, ?string $sqlState, ?string $me /** @var DriverExceptionInterface|MockObject $driverException */ $driverException = $this->getMockBuilder(DriverExceptionInterface::class) - ->setConstructorArgs([$message]) + ->setConstructorArgs([$message, $errorCode]) ->getMock(); - $driverException->method('getErrorCode') - ->willReturn($errorCode); $driverException->method('getSQLState') ->willReturn($sqlState); @@ -93,7 +91,7 @@ public function testConvertsException($errorCode, ?string $sqlState, ?string $me self::assertInstanceOf($expectedClass, $dbalException); - self::assertSame($driverException->getErrorCode(), $dbalException->getErrorCode()); + self::assertSame($driverException->getCode(), $dbalException->getCode()); self::assertSame($driverException->getSQLState(), $dbalException->getSQLState()); self::assertSame($driverException, $dbalException->getPrevious()); self::assertSame($dbalMessage, $dbalException->getMessage()); @@ -200,6 +198,9 @@ abstract protected function createPlatform() : AbstractPlatform; */ abstract protected function createSchemaManager(Connection $connection) : AbstractSchemaManager; + /** + * @return Connection|MockObject + */ protected function getConnectionMock() : Connection { return $this->getMockBuilder(Connection::class) @@ -222,11 +223,11 @@ public static function exceptionConversionProvider() : iterable { foreach (static::getExceptionConversionData() as $expectedClass => $items) { foreach ($items as $item) { - yield array_merge($item, [$expectedClass]); + yield array_merge([$expectedClass], $item); } } - yield ['foo', 'bar', 'baz', self::EXCEPTION_DRIVER]; + yield [self::EXCEPTION_DRIVER, 1, 'HY000', 'The message']; } /** diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php index 4982a189e05..2d831dbd41f 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php @@ -1,5 +1,7 @@ [ - ['1044', null, null], - ['1045', null, null], - ['1046', null, null], - ['1049', null, null], - ['1095', null, null], - ['1142', null, null], - ['1143', null, null], - ['1227', null, null], - ['1370', null, null], - ['2002', null, null], - ['2005', null, null], + [1044], + [1045], + [1046], + [1049], + [1095], + [1142], + [1143], + [1227], + [1370], + [2002], + [2005], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['1216', null, null], - ['1217', null, null], - ['1451', null, null], - ['1452', null, null], + [1216], + [1217], + [1451], + [1452], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['1054', null, null], - ['1166', null, null], - ['1611', null, null], + [1054], + [1166], + [1611], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['1052', null, null], - ['1060', null, null], - ['1110', null, null], + [1052], + [1060], + [1110], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['1048', null, null], - ['1121', null, null], - ['1138', null, null], - ['1171', null, null], - ['1252', null, null], - ['1263', null, null], - ['1364', null, null], - ['1566', null, null], + [1048], + [1121], + [1138], + [1171], + [1252], + [1263], + [1364], + [1566], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['1064', null, null], - ['1149', null, null], - ['1287', null, null], - ['1341', null, null], - ['1342', null, null], - ['1343', null, null], - ['1344', null, null], - ['1382', null, null], - ['1479', null, null], - ['1541', null, null], - ['1554', null, null], - ['1626', null, null], + [1064], + [1149], + [1287], + [1341], + [1342], + [1343], + [1344], + [1382], + [1479], + [1541], + [1554], + [1626], ], self::EXCEPTION_TABLE_EXISTS => [ - ['1050', null, null], + [1050], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['1051', null, null], - ['1146', null, null], + [1051], + [1146], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['1062', null, null], - ['1557', null, null], - ['1569', null, null], - ['1586', null, null], + [1062], + [1557], + [1569], + [1586], ], self::EXCEPTION_DEADLOCK => [ - ['1213', null, null], + [1213], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - ['1205', null, null], + [1205], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriver/EasyConnectStringTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriver/EasyConnectStringTest.php index efb250d1ac7..192ba76144a 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriver/EasyConnectStringTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriver/EasyConnectStringTest.php @@ -1,5 +1,7 @@ > */ public static function connectionParametersProvider() : iterable { diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php index f95705a8a88..f5862eb12de 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php @@ -1,5 +1,7 @@ [ - ['1017', null, null], - ['12545', null, null], + [1017], + [12545], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['2292', null, null], + [2292], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['904', null, null], + [904], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['918', null, null], - ['960', null, null], + [918], + [960], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['1400', null, null], + [1400], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['923', null, null], + [923], ], self::EXCEPTION_TABLE_EXISTS => [ - ['955', null, null], + [955], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['942', null, null], + [942], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['1', null, null], - ['2299', null, null], - ['38911', null, null], + [1], + [2299], + [38911], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php index 2ba6a732bd4..9a698d92f4d 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php @@ -1,5 +1,7 @@ [ - [null, '7', 'SQLSTATE[08006]'], + [7, null, 'SQLSTATE[08006]'], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - [null, '23503', null], + [0, '23503'], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - [null, '42703', null], + [0, '42703'], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - [null, '42702', null], + [0, '42702'], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - [null, '23502', null], + [0, '23502'], ], self::EXCEPTION_SYNTAX_ERROR => [ - [null, '42601', null], + [0, '42601'], ], self::EXCEPTION_TABLE_EXISTS => [ - [null, '42P07', null], + [0, '42P07'], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - [null, '42P01', null], + [0, '42P01'], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - [null, '23505', null], + [0, '23505'], ], self::EXCEPTION_DEADLOCK => [ - [null, '40001', null], - [null, '40P01', null], + [0, '40001'], + [0, '40P01'], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php index 4c51e7cb35f..8931dc6069a 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php @@ -1,14 +1,13 @@ [ - ['-100', null, null], - ['-103', null, null], - ['-832', null, null], + [-100], + [-103], + [-832], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ - ['-198', null, null], + [-198], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - ['-143', null, null], + [-143], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - ['-144', null, null], + [-144], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - ['-184', null, null], - ['-195', null, null], + [-184], + [-195], ], self::EXCEPTION_SYNTAX_ERROR => [ - ['-131', null, null], + [-131], ], self::EXCEPTION_TABLE_EXISTS => [ - ['-110', null, null], + [-110], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - ['-141', null, null], - ['-1041', null, null], + [-141], + [-1041], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - ['-193', null, null], - ['-196', null, null], + [-193], + [-196], ], self::EXCEPTION_DEADLOCK => [ - ['-306', null, null], - ['-307', null, null], - ['-684', null, null], + [-306], + [-307], + [-684], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - ['-210', null, null], - ['-1175', null, null], - ['-1281', null, null], + [-210], + [-1175], + [-1281], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php index 0d34df8e81b..4e650548d57 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php @@ -1,13 +1,13 @@ [ - [null, null, 'unable to open database file'], + [0, null, 'unable to open database file'], ], self::EXCEPTION_INVALID_FIELD_NAME => [ - [null, null, 'has no column named'], + [0, null, 'has no column named'], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ - [null, null, 'ambiguous column name'], + [0, null, 'ambiguous column name'], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ - [null, null, 'may not be NULL'], + [0, null, 'may not be NULL'], ], self::EXCEPTION_READ_ONLY => [ - [null, null, 'attempt to write a readonly database'], + [0, null, 'attempt to write a readonly database'], ], self::EXCEPTION_SYNTAX_ERROR => [ - [null, null, 'syntax error'], + [0, null, 'syntax error'], ], self::EXCEPTION_TABLE_EXISTS => [ - [null, null, 'already exists'], + [0, null, 'already exists'], ], self::EXCEPTION_TABLE_NOT_FOUND => [ - [null, null, 'no such table:'], + [0, null, 'no such table:'], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ - [null, null, 'must be unique'], - [null, null, 'is not unique'], - [null, null, 'are not unique'], + [0, null, 'must be unique'], + [0, null, 'is not unique'], + [0, null, 'are not unique'], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ - [null, null, 'database is locked'], + [0, null, 'database is locked'], ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php deleted file mode 100644 index 5af24b8454a..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php +++ /dev/null @@ -1,52 +0,0 @@ -driver->getName()); - } - - public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() : void - { - $this->markTestSkipped('This test does not work on Drizzle as it is not version aware.'); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } - - protected function createPlatform() : AbstractPlatform - { - return new DrizzlePlatform(); - } - - protected function createSchemaManager(Connection $connection) : AbstractSchemaManager - { - return new DrizzleSchemaManager($connection); - } - - /** - * @return mixed[][] - */ - protected function getDatabasePlatformsForVersions() : array - { - return [ - ['foo', DrizzlePlatform::class], - ['bar', DrizzlePlatform::class], - ['baz', DrizzlePlatform::class], - ]; - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2ConnectionTest.php index cf2db940b33..db4270d5652 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2ConnectionTest.php @@ -1,5 +1,7 @@ driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new DB2Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/DriverTest.php deleted file mode 100644 index bbe16b34717..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/Exception/UnknownTypeTest.php b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/Exception/UnknownTypeTest.php new file mode 100644 index 00000000000..cc3aedd358c --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/Exception/UnknownTypeTest.php @@ -0,0 +1,18 @@ +getMessage()); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php index dcfbe715608..2aa575b511f 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php @@ -1,9 +1,11 @@ '255.255.255.255'], 'user', 'pass'); self::fail('An exception was supposed to be raised'); - } catch (MysqliException $e) { - self::assertSame('Network is unreachable', $e->getMessage()); + } catch (ConnectionError $e) { + // Do nothing } - self::assertSame($handler, set_error_handler($default_handler), 'Restoring error handler failed.'); + self::assertSame($handler, set_error_handler($handler), 'Restoring error handler failed.'); restore_error_handler(); restore_error_handler(); } diff --git a/tests/Doctrine/Tests/DBAL/Driver/OCI8/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/OCI8/DriverTest.php deleted file mode 100644 index 7b6ed1d5a55..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/OCI8/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8ConnectionTest.php index 4c3868f4a95..0c54cc88c6c 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8ConnectionTest.php @@ -1,5 +1,7 @@ getMockBuilder(OCI8Statement::class) - ->setMethods(['bindValue', 'errorInfo']) + ->setMethods(['bindValue']) ->disableOriginalConstructor() ->getMock(); - $statement->expects($this->at(0)) - ->method('bindValue') - ->with( - $this->equalTo(1), - $this->equalTo($params[0]) - ); - $statement->expects($this->at(1)) - ->method('bindValue') - ->with( - $this->equalTo(2), - $this->equalTo($params[1]) - ); - $statement->expects($this->at(2)) - ->method('bindValue') - ->with( - $this->equalTo(3), - $this->equalTo($params[2]) - ); + foreach ($params as $index => $value) { + $statement->expects($this->at($index)) + ->method('bindValue') + ->with( + $this->equalTo($index + 1), + $this->equalTo($value) + ) + ->willReturn(true); + } // can't pass to constructor since we don't have a real database handle, // but execute must check the connection for the executeMode - $conn = $this->getMockBuilder(OCI8Connection::class) - ->setMethods(['getExecuteMode']) - ->disableOriginalConstructor() - ->getMock(); + $conn = $this->createMock(OCI8Connection::class); $conn->expects($this->once()) - ->method('getExecuteMode'); + ->method('getExecuteMode') + ->willReturn(OCI_NO_AUTO_COMMIT); + + $connectionReflection = new ReflectionProperty($statement, '_conn'); + $connectionReflection->setAccessible(true); + $connectionReflection->setValue($statement, $conn); - $reflProperty = new ReflectionProperty($statement, '_conn'); - $reflProperty->setAccessible(true); - $reflProperty->setValue($statement, $conn); + $handleReflection = new ReflectionProperty($statement, '_sth'); + $handleReflection->setAccessible(true); + $handleReflection->setValue($statement, fopen('php://temp', 'r')); $this->expectException(OCI8Exception::class); $statement->execute($params); @@ -111,15 +110,15 @@ public static function nonTerminatedLiteralProvider() : iterable return [ 'no-matching-quote' => [ "SELECT 'literal FROM DUAL", - '/offset 7/', + '/offset 7./', ], 'no-matching-double-quote' => [ 'SELECT 1 "COL1 FROM DUAL', - '/offset 9/', + '/offset 9./', ], 'incorrect-escaping-syntax' => [ "SELECT 'quoted \\'string' FROM DUAL", - '/offset 23/', + '/offset 23./', ], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php index 9ed9a06aa5b..c35b5515099 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php @@ -1,19 +1,22 @@ markTestSkipped('PDO is not installed.'); - } - parent::setUp(); - $this->wrappedException = new \PDOException(self::MESSAGE, self::SQLSTATE); + $this->wrappedException = new \PDOException(self::MESSAGE); $this->wrappedException->errorInfo = [self::SQLSTATE, self::ERROR_CODE]; @@ -46,12 +45,7 @@ protected function setUp() : void public function testReturnsCode() : void { - self::assertSame(self::SQLSTATE, $this->exception->getCode()); - } - - public function testReturnsErrorCode() : void - { - self::assertSame(self::ERROR_CODE, $this->exception->getErrorCode()); + self::assertSame(self::ERROR_CODE, $this->exception->getCode()); } public function testReturnsMessage() : void diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php deleted file mode 100644 index 9eeeafb78aa..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOMySql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOMySql/DriverTest.php deleted file mode 100644 index 6e3ef7d5a03..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOMySql/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOOracle/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOOracle/DriverTest.php deleted file mode 100644 index 42353be376d..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOOracle/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php index 2b976233c27..940fc3bc1c5 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php @@ -1,5 +1,7 @@ driver->getName()); + parent::setUp(); + + if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] === 'pdo_pgsql') { + return; + } + + $this->markTestSkipped('Test enabled only when using pdo_pgsql specific phpunit.xml'); } /** * @group DBAL-920 */ - public function testConnectionDisablesPreparesOnPhp56() : void + public function testConnectionDisablesPrepares() : void { - $this->skipWhenNotUsingPhp56AndPdoPgsql(); - $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], @@ -34,22 +38,16 @@ public function testConnectionDisablesPreparesOnPhp56() : void ); self::assertInstanceOf(PDOConnection::class, $connection); - - try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); - } catch (PDOException $ignored) { - /** @link https://bugs.php.net/bug.php?id=68371 */ - $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); - } + self::assertTrue( + $connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES) + ); } /** * @group DBAL-920 */ - public function testConnectionDoesNotDisablePreparesOnPhp56WhenAttributeDefined() : void + public function testConnectionDoesNotDisablePreparesWhenAttributeDefined() : void { - $this->skipWhenNotUsingPhp56AndPdoPgsql(); - $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], @@ -61,22 +59,16 @@ public function testConnectionDoesNotDisablePreparesOnPhp56WhenAttributeDefined( ); self::assertInstanceOf(PDOConnection::class, $connection); - - try { - self::assertNotSame(true, $connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); - } catch (PDOException $ignored) { - /** @link https://bugs.php.net/bug.php?id=68371 */ - $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); - } + self::assertNotTrue( + $connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES) + ); } /** * @group DBAL-920 */ - public function testConnectionDisablePreparesOnPhp56WhenDisablePreparesIsExplicitlyDefined() : void + public function testConnectionDisablePreparesWhenDisablePreparesIsExplicitlyDefined() : void { - $this->skipWhenNotUsingPhp56AndPdoPgsql(); - $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], @@ -88,13 +80,9 @@ public function testConnectionDisablePreparesOnPhp56WhenDisablePreparesIsExplici ); self::assertInstanceOf(PDOConnection::class, $connection); - - try { - self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); - } catch (PDOException $ignored) { - /** @link https://bugs.php.net/bug.php?id=68371 */ - $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); - } + self::assertTrue( + $connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES) + ); } /** @@ -104,17 +92,4 @@ protected function createDriver() : DriverInterface { return new Driver(); } - - private function skipWhenNotUsingPhp56AndPdoPgsql() : void - { - if (! defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')) { - $this->markTestSkipped('Test requires PHP 5.6+'); - } - - if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] === 'pdo_pgsql') { - return; - } - - $this->markTestSkipped('Test enabled only when using pdo_pgsql specific phpunit.xml'); - } } diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOSqlite/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOSqlite/DriverTest.php deleted file mode 100644 index 9092b091e3a..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOSqlite/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/PDOSqlsrv/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/PDOSqlsrv/DriverTest.php deleted file mode 100644 index c92dc86d5ba..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/PDOSqlsrv/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/DriverTest.php b/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/DriverTest.php deleted file mode 100644 index d6f1595a45e..00000000000 --- a/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/DriverTest.php +++ /dev/null @@ -1,20 +0,0 @@ -driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/SQLAnywhereConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/SQLAnywhereConnectionTest.php index effeb483362..d78a95fa6da 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/SQLAnywhereConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/SQLAnywhereConnectionTest.php @@ -1,5 +1,7 @@ driver->getName()); - } - - protected function createDriver() : DriverInterface - { - return new Driver(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/SQLSrvConnectionTest.php b/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/SQLSrvConnectionTest.php index 8d457d8eb23..4225e65c2dd 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/SQLSrvConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/SQLSrvConnectionTest.php @@ -1,5 +1,7 @@ |MockObject $stmt */ $stmt = $this->createPartialMock($class, ['fetch']); $calls = 0; $this->configureStatement($stmt, $calls); + $this->assertIterationCallsFetchOncePerStep($stmt, $calls); } @@ -71,13 +74,6 @@ private function configureStatement(MockObject $stmt, int &$calls) : void }); } - private function assertIterationCallsFetchOncePerStep(Traversable $iterator, int &$calls) : void - { - foreach ($iterator as $i => $_) { - $this->assertEquals($i + 1, $calls); - } - } - /** * @return string[][] */ @@ -100,4 +96,14 @@ public static function statementProvider() : iterable yield [SQLSrvStatement::class]; } } + + /** + * @param iterable $iterator + */ + private function assertIterationCallsFetchOncePerStep(iterable $iterator, int &$calls) : void + { + foreach ($iterator as $i => $_) { + $this->assertEquals($i + 1, $calls); + } + } } diff --git a/tests/Doctrine/Tests/DBAL/DriverManagerTest.php b/tests/Doctrine/Tests/DBAL/DriverManagerTest.php index ced3e5d993f..3aac0b84e72 100644 --- a/tests/Doctrine/Tests/DBAL/DriverManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/DriverManagerTest.php @@ -1,12 +1,13 @@ expectException(DBALException::class); - DriverManager::getConnection(['pdo' => 'test']); - } - - /** - * @requires extension pdo_sqlite - */ - public function testValidPdoInstance() : void - { - $conn = DriverManager::getConnection([ - 'pdo' => new PDO('sqlite::memory:'), - ]); - - self::assertEquals('sqlite', $conn->getDatabasePlatform()->getName()); - } - - /** - * @group DBAL-32 - * @requires extension pdo_sqlite - */ - public function testPdoInstanceSetErrorMode() : void - { - $pdo = new PDO('sqlite::memory:'); - $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); - $options = ['pdo' => $pdo]; - - DriverManager::getConnection($options); - self::assertEquals(PDO::ERRMODE_EXCEPTION, $pdo->getAttribute(PDO::ATTR_ERRMODE)); - } - public function testCheckParams() : void { $this->expectException(DBALException::class); @@ -80,7 +44,7 @@ public function testCustomPlatform() : void { $platform = $this->createMock(AbstractPlatform::class); $options = [ - 'pdo' => new PDO('sqlite::memory:'), + 'url' => 'sqlite::memory:', 'platform' => $platform, ]; @@ -97,7 +61,7 @@ public function testCustomWrapper() : void $wrapperClass = get_class($wrapper); $options = [ - 'pdo' => new PDO('sqlite::memory:'), + 'url' => 'sqlite::memory:', 'wrapperClass' => $wrapperClass, ]; @@ -113,7 +77,7 @@ public function testInvalidWrapperClass() : void $this->expectException(DBALException::class); $options = [ - 'pdo' => new PDO('sqlite::memory:'), + 'url' => 'sqlite::memory:', 'wrapperClass' => stdClass::class, ]; @@ -215,16 +179,6 @@ public function testDatabaseUrl($url, $expected) : void { $options = is_array($url) ? $url : ['url' => $url]; - if (isset($options['pdo'])) { - if (! extension_loaded('pdo')) { - $this->markTestSkipped('PDO is not installed'); - } - - $options['pdo'] = $this->createMock(PDO::class); - } - - $options = is_array($url) ? $url : ['url' => $url]; - if ($expected === false) { $this->expectException(DBALException::class); } @@ -233,7 +187,7 @@ public function testDatabaseUrl($url, $expected) : void $params = $conn->getParams(); foreach ($expected as $key => $value) { - if (in_array($key, ['pdo', 'driver', 'driverClass'], true)) { + if (in_array($key, ['driver', 'driverClass'], true)) { self::assertInstanceOf($value, $conn->getDriver()); } else { self::assertEquals($value, $params[$key]); @@ -242,7 +196,7 @@ public function testDatabaseUrl($url, $expected) : void } /** - * @return array> + * @return array */ public function databaseUrls() : iterable { @@ -355,17 +309,17 @@ public function databaseUrls() : iterable ], ], 'simple URL with fallthrough scheme containing underscores fails' => [ - 'drizzle_pdo_mysql://foo:bar@localhost/baz', + 'pdo_mysql://foo:bar@localhost/baz', false, ], 'simple URL with fallthrough scheme containing dashes works' => [ - 'drizzle-pdo-mysql://foo:bar@localhost/baz', + 'pdo-mysql://foo:bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', - 'driver' => DrizzlePDOMySqlDriver::class, + 'driver' => PDOMySQLDriver::class, ], ], 'simple URL with percent encoding' => [ @@ -394,13 +348,6 @@ public function databaseUrls() : iterable ['url' => '//foo:bar@localhost/baz'], false, ], - 'URL without scheme but default PDO driver' => [ - [ - 'url' => '//foo:bar@localhost/baz', - 'pdo' => true, - ], - false, - ], 'URL without scheme but default driver' => [ [ 'url' => '//foo:bar@localhost/baz', @@ -427,20 +374,6 @@ public function databaseUrls() : iterable 'driverClass' => $driverClass, ], ], - 'URL without scheme but default PDO driver and default driver' => [ - [ - 'url' => '//foo:bar@localhost/baz', - 'pdo' => true, - 'driver' => 'pdo_mysql', - ], - [ - 'user' => 'foo', - 'password' => 'bar', - 'host' => 'localhost', - 'dbname' => 'baz', - 'driver' => PDOMySQLDriver::class, - ], - ], 'URL without scheme but driver and custom driver' => [ [ 'url' => '//foo:bar@localhost/baz', @@ -455,19 +388,6 @@ public function databaseUrls() : iterable 'driverClass' => $driverClass, ], ], - 'URL with default PDO driver' => [ - [ - 'url' => 'mysql://foo:bar@localhost/baz', - 'pdo' => true, - ], - [ - 'user' => 'foo', - 'password' => 'bar', - 'host' => 'localhost', - 'dbname' => 'baz', - 'driver' => PDOMySQLDriver::class, - ], - ], 'URL with default driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', @@ -494,20 +414,6 @@ public function databaseUrls() : iterable 'driver' => PDOMySQLDriver::class, ], ], - 'URL with default PDO driver and default driver' => [ - [ - 'url' => 'mysql://foo:bar@localhost/baz', - 'pdo' => true, - 'driver' => 'sqlite', - ], - [ - 'user' => 'foo', - 'password' => 'bar', - 'host' => 'localhost', - 'dbname' => 'baz', - 'driver' => PDOMySQLDriver::class, - ], - ], 'URL with default driver and default custom driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', @@ -522,21 +428,6 @@ public function databaseUrls() : iterable 'driver' => PDOMySQLDriver::class, ], ], - 'URL with default PDO driver and default driver and default custom driver' => [ - [ - 'url' => 'mysql://foo:bar@localhost/baz', - 'pdo' => true, - 'driver' => 'sqlite', - 'driverClass' => $driverClass, - ], - [ - 'user' => 'foo', - 'password' => 'bar', - 'host' => 'localhost', - 'dbname' => 'baz', - 'driver' => PDOMySQLDriver::class, - ], - ], ]; } } diff --git a/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php b/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php deleted file mode 100644 index daea3a754c6..00000000000 --- a/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php +++ /dev/null @@ -1,31 +0,0 @@ -createMock(Connection::class); - $connectionMock->expects($this->once()) - ->method('executeUpdate') - ->with($this->equalTo('SET NAMES foo COLLATE bar')); - - $eventArgs = new ConnectionEventArgs($connectionMock); - - $listener = new MysqlSessionInit('foo', 'bar'); - $listener->postConnect($eventArgs); - } - - public function testGetSubscribedEvents() : void - { - $listener = new MysqlSessionInit(); - self::assertEquals([Events::postConnect], $listener->getSubscribedEvents()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php b/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php index 998b1dc916e..88fbc34a00f 100644 --- a/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php +++ b/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php @@ -1,5 +1,7 @@ getMessage() + ); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Exception/EmptyCriteriaNotAllowedTest.php b/tests/Doctrine/Tests/DBAL/Exception/EmptyCriteriaNotAllowedTest.php new file mode 100644 index 00000000000..e67de9b916e --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Exception/EmptyCriteriaNotAllowedTest.php @@ -0,0 +1,20 @@ +getMessage()); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Exception/GetVariableTypeTest.php b/tests/Doctrine/Tests/DBAL/Exception/GetVariableTypeTest.php new file mode 100644 index 00000000000..8ae6b3082c5 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Exception/GetVariableTypeTest.php @@ -0,0 +1,42 @@ +__invoke($value)); + } + + /** + * @return array> + */ + public function provideDataForFormatVariable() : array + { + return [ + ['string', ''], + ['string', 'test'], + ['double', 1.0], + ['integer', 1], + ['NULL', null], + ['stdClass', new stdClass()], + ['stream', tmpfile()], + ['true', true], + ['false', false], + ['array', [true, 1, 2, 3, 'test']], + ]; + } +} diff --git a/tests/Doctrine/Tests/DBAL/Exception/InvalidArgumentExceptionTest.php b/tests/Doctrine/Tests/DBAL/Exception/InvalidArgumentExceptionTest.php deleted file mode 100644 index 7718a6bc9d8..00000000000 --- a/tests/Doctrine/Tests/DBAL/Exception/InvalidArgumentExceptionTest.php +++ /dev/null @@ -1,22 +0,0 @@ -getMessage()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Exception/InvalidColumnIndexTest.php b/tests/Doctrine/Tests/DBAL/Exception/InvalidColumnIndexTest.php new file mode 100644 index 00000000000..ec55bad9cd2 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Exception/InvalidColumnIndexTest.php @@ -0,0 +1,28 @@ +getMessage()); + } + + public function testNewPlural() : void + { + $exception = InvalidColumnIndex::new(5, 2); + + self::assertInstanceOf(DBALException::class, $exception); + self::assertSame('Invalid column index 5. The statement result contains 2 columns.', $exception->getMessage()); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Exception/InvalidPlatformTypeTest.php b/tests/Doctrine/Tests/DBAL/Exception/InvalidPlatformTypeTest.php new file mode 100644 index 00000000000..3b8ea6f81a2 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Exception/InvalidPlatformTypeTest.php @@ -0,0 +1,38 @@ +getMessage() + ); + } + + /** + * @group #2821 + */ + public function testInvalidPlatformTypeScalar() : void + { + $exception = InvalidPlatformType::new('some string'); + + self::assertSame( + 'Option "platform" must be an object and subtype of Doctrine\DBAL\Platforms\AbstractPlatform. Got string.', + $exception->getMessage() + ); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php b/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php index a12d0600201..c3a14419276 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php @@ -1,5 +1,7 @@ connection->quote('foo', Types::STRING), - $this->connection->quote('foo', ParameterType::STRING) - ); - } - public function testPingDoesTriggersConnect() : void { - self::assertTrue($this->connection->ping()); + $this->connection->close(); + self::assertFalse($this->connection->isConnected()); + + $this->connection->ping(); self::assertTrue($this->connection->isConnected()); } @@ -282,7 +278,9 @@ public function testConnectWithoutExplicitDatabaseName() : void $this->connection->getEventManager() ); - self::assertTrue($connection->connect()); + $connection->connect(); + + self::assertTrue($connection->isConnected()); $connection->close(); } @@ -313,15 +311,27 @@ public function testDeterminesDatabasePlatformWhenConnectingToNonExistentDatabas $connection->close(); } - /** - * @requires extension pdo_sqlite - */ - public function testUserProvidedPDOConnection() : void + public function testPersistentConnection() : void { - self::assertTrue( - DriverManager::getConnection([ - 'pdo' => new PDO('sqlite::memory:'), - ])->ping() - ); + $platform = $this->connection->getDatabasePlatform(); + + if ($platform instanceof SqlitePlatform + || $platform instanceof SQLServerPlatform) { + self::markTestSkipped('The platform does not support persistent connections'); + } + + $params = TestUtil::getConnectionParams(); + $params['persistent'] = true; + + $connection = DriverManager::getConnection($params); + $driverConnection = $connection->getWrappedConnection(); + + if (! $driverConnection instanceof PDOConnection) { + self::markTestSkipped('Unable to test if the connection is persistent'); + } + + $pdo = $driverConnection->getWrappedConnection(); + + self::assertTrue($pdo->getAttribute(PDO::ATTR_PERSISTENT)); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php index b7d625c8600..eafa033c0b0 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -1,5 +1,7 @@ addColumn('test_int', 'integer'); - $table->addColumn('test_string', 'string'); + $table->addColumn('test_string', 'string', ['length' => 32]); $table->addColumn('test_datetime', 'datetime', ['notnull' => false]); $table->setPrimaryKey(['test_int']); @@ -177,9 +183,9 @@ public function testPrepareWithQuoted() : void $paramStr = 'foo'; $stmt = $this->connection->prepare(sprintf( - 'SELECT test_int, test_string FROM %s WHERE test_int = %s AND test_string = %s', + 'SELECT test_int, test_string FROM %s WHERE test_int = %d AND test_string = %s', $this->connection->quoteIdentifier($table), - $this->connection->quote($paramInt), + $paramInt, $this->connection->quote($paramStr) )); self::assertInstanceOf(Statement::class, $stmt); @@ -508,17 +514,17 @@ public function testNativeArrayListSupport() : void } /** - * @param string|false $char - * * @dataProvider getTrimExpressionData */ - public function testTrimExpression(string $value, int $position, $char, string $expectedResult) : void + public function testTrimExpression(string $value, int $position, ?string $char, string $expectedResult) : void { $sql = 'SELECT ' . $this->connection->getDatabasePlatform()->getTrimExpression($value, $position, $char) . ' AS trimmed ' . 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); + self::assertIsArray($row); + $row = array_change_key_case($row, CASE_LOWER); self::assertEquals($expectedResult, $row['trimmed']); @@ -530,10 +536,10 @@ public function testTrimExpression(string $value, int $position, $char, string $ public static function getTrimExpressionData() : iterable { return [ - ['test_string', TrimMode::UNSPECIFIED, false, 'foo'], - ['test_string', TrimMode::LEADING, false, 'foo'], - ['test_string', TrimMode::TRAILING, false, 'foo'], - ['test_string', TrimMode::BOTH, false, 'foo'], + ['test_string', TrimMode::UNSPECIFIED, null, 'foo'], + ['test_string', TrimMode::LEADING, null, 'foo'], + ['test_string', TrimMode::TRAILING, null, 'foo'], + ['test_string', TrimMode::BOTH, null, 'foo'], ['test_string', TrimMode::UNSPECIFIED, "'f'", 'oo'], ['test_string', TrimMode::UNSPECIFIED, "'o'", 'f'], ['test_string', TrimMode::UNSPECIFIED, "'.'", 'foo'], @@ -546,10 +552,10 @@ public static function getTrimExpressionData() : iterable ['test_string', TrimMode::BOTH, "'f'", 'oo'], ['test_string', TrimMode::BOTH, "'o'", 'f'], ['test_string', TrimMode::BOTH, "'.'", 'foo'], - ["' foo '", TrimMode::UNSPECIFIED, false, 'foo'], - ["' foo '", TrimMode::LEADING, false, 'foo '], - ["' foo '", TrimMode::TRAILING, false, ' foo'], - ["' foo '", TrimMode::BOTH, false, 'foo'], + ["' foo '", TrimMode::UNSPECIFIED, null, 'foo'], + ["' foo '", TrimMode::LEADING, null, 'foo '], + ["' foo '", TrimMode::TRAILING, null, ' foo'], + ["' foo '", TrimMode::BOTH, null, 'foo'], ["' foo '", TrimMode::UNSPECIFIED, "'f'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'o'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'.'", ' foo '], @@ -569,50 +575,320 @@ public static function getTrimExpressionData() : iterable ]; } + public function testTrimExpressionInvalidMode() : void + { + $this->expectException(InvalidArgumentException::class); + $this->connection->getDatabasePlatform()->getTrimExpression('Trim me!', 0xBEEF); + } + /** - * @group DDC-1014 + * @dataProvider modeProvider */ - public function testDateArithmetics() : void + public function testDateAddSeconds(callable $buildQuery, callable $bindParams) : void { - $p = $this->connection->getDatabasePlatform(); - $sql = 'SELECT '; - $sql .= $p->getDateAddSecondsExpression('test_datetime', 1) . ' AS add_seconds, '; - $sql .= $p->getDateSubSecondsExpression('test_datetime', 1) . ' AS sub_seconds, '; - $sql .= $p->getDateAddMinutesExpression('test_datetime', 5) . ' AS add_minutes, '; - $sql .= $p->getDateSubMinutesExpression('test_datetime', 5) . ' AS sub_minutes, '; - $sql .= $p->getDateAddHourExpression('test_datetime', 3) . ' AS add_hour, '; - $sql .= $p->getDateSubHourExpression('test_datetime', 3) . ' AS sub_hour, '; - $sql .= $p->getDateAddDaysExpression('test_datetime', 10) . ' AS add_days, '; - $sql .= $p->getDateSubDaysExpression('test_datetime', 10) . ' AS sub_days, '; - $sql .= $p->getDateAddWeeksExpression('test_datetime', 1) . ' AS add_weeks, '; - $sql .= $p->getDateSubWeeksExpression('test_datetime', 1) . ' AS sub_weeks, '; - $sql .= $p->getDateAddMonthExpression('test_datetime', 2) . ' AS add_month, '; - $sql .= $p->getDateSubMonthExpression('test_datetime', 2) . ' AS sub_month, '; - $sql .= $p->getDateAddQuartersExpression('test_datetime', 3) . ' AS add_quarters, '; - $sql .= $p->getDateSubQuartersExpression('test_datetime', 3) . ' AS sub_quarters, '; - $sql .= $p->getDateAddYearsExpression('test_datetime', 6) . ' AS add_years, '; - $sql .= $p->getDateSubYearsExpression('test_datetime', 6) . ' AS sub_years '; - $sql .= 'FROM fetch_table'; + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddSecondsExpression('test_datetime', $interval); + }, + 1, + '2010-01-01 10:10:11' + ); + } - $row = $this->connection->fetchAssoc($sql); - $row = array_change_key_case($row, CASE_LOWER); + /** + * @dataProvider modeProvider + */ + public function testDateSubSeconds(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubSecondsExpression('test_datetime', $interval); + }, + 1, + '2010-01-01 10:10:09' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddMinutes(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddMinutesExpression('test_datetime', $interval); + }, + 5, + '2010-01-01 10:15:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubMinutes(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubMinutesExpression('test_datetime', $interval); + }, + 5, + '2010-01-01 10:05:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddHours(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddHourExpression('test_datetime', $interval); + }, + 3, + '2010-01-01 13:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubHours(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubHourExpression('test_datetime', $interval); + }, + 3, + '2010-01-01 07:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddDays(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddDaysExpression('test_datetime', $interval); + }, + 10, + '2010-01-11 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubDays(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubDaysExpression('test_datetime', $interval); + }, + 10, + '2009-12-22 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddWeeks(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddWeeksExpression('test_datetime', $interval); + }, + 1, + '2010-01-08 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubWeeks(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubWeeksExpression('test_datetime', $interval); + }, + 1, + '2009-12-25 10:10:10' + ); + } - self::assertEquals('2010-01-01 10:10:11', date('Y-m-d H:i:s', strtotime($row['add_seconds'])), 'Adding second should end up on 2010-01-01 10:10:11'); - self::assertEquals('2010-01-01 10:10:09', date('Y-m-d H:i:s', strtotime($row['sub_seconds'])), 'Subtracting second should end up on 2010-01-01 10:10:09'); - self::assertEquals('2010-01-01 10:15:10', date('Y-m-d H:i:s', strtotime($row['add_minutes'])), 'Adding minutes should end up on 2010-01-01 10:15:10'); - self::assertEquals('2010-01-01 10:05:10', date('Y-m-d H:i:s', strtotime($row['sub_minutes'])), 'Subtracting minutes should end up on 2010-01-01 10:05:10'); - self::assertEquals('2010-01-01 13:10', date('Y-m-d H:i', strtotime($row['add_hour'])), 'Adding date should end up on 2010-01-01 13:10'); - self::assertEquals('2010-01-01 07:10', date('Y-m-d H:i', strtotime($row['sub_hour'])), 'Subtracting date should end up on 2010-01-01 07:10'); - self::assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), 'Adding date should end up on 2010-01-11'); - self::assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), 'Subtracting date should end up on 2009-12-22'); - self::assertEquals('2010-01-08', date('Y-m-d', strtotime($row['add_weeks'])), 'Adding week should end up on 2010-01-08'); - self::assertEquals('2009-12-25', date('Y-m-d', strtotime($row['sub_weeks'])), 'Subtracting week should end up on 2009-12-25'); - self::assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), 'Adding month should end up on 2010-03-01'); - self::assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), 'Subtracting month should end up on 2009-11-01'); - self::assertEquals('2010-10-01', date('Y-m-d', strtotime($row['add_quarters'])), 'Adding quarters should end up on 2010-04-01'); - self::assertEquals('2009-04-01', date('Y-m-d', strtotime($row['sub_quarters'])), 'Subtracting quarters should end up on 2009-10-01'); - self::assertEquals('2016-01-01', date('Y-m-d', strtotime($row['add_years'])), 'Adding years should end up on 2016-01-01'); - self::assertEquals('2004-01-01', date('Y-m-d', strtotime($row['sub_years'])), 'Subtracting years should end up on 2004-01-01'); + /** + * @dataProvider modeProvider + */ + public function testDateAddMonths(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddMonthExpression('test_datetime', $interval); + }, + 2, + '2010-03-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubMonths(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubMonthExpression('test_datetime', $interval); + }, + 2, + '2009-11-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddQuarters(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddQuartersExpression('test_datetime', $interval); + }, + 3, + '2010-10-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubQuarters(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubQuartersExpression('test_datetime', $interval); + }, + 3, + '2009-04-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateAddYears(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateAddYearsExpression('test_datetime', $interval); + }, + 6, + '2016-01-01 10:10:10' + ); + } + + /** + * @dataProvider modeProvider + */ + public function testDateSubYears(callable $buildQuery, callable $bindParams) : void + { + $this->assertDateExpression( + $buildQuery, + $bindParams, + static function (AbstractPlatform $platform, string $interval) : string { + return $platform->getDateSubYearsExpression('test_datetime', $interval); + }, + 6, + '2004-01-01 10:10:10' + ); + } + + /** + * @param callable $buildQuery Builds the portion of the query representing the interval value + * @param callable $bindParams Binds the interval value to the statement + * @param callable $expression Builds the platform-specific interval expression + * @param int $interval Interval value + * @param string $expected Expected value + */ + private function assertDateExpression(callable $buildQuery, callable $bindParams, callable $expression, int $interval, string $expected) : void + { + $connection = $this->connection; + $platform = $connection->getDatabasePlatform(); + + $query = sprintf('SELECT %s FROM fetch_table', $expression($platform, $buildQuery($interval))); + $stmt = $connection->prepare($query); + $bindParams($stmt, $interval); + + $stmt->execute(); + + $date = $stmt->fetchColumn(); + + $this->assertEquals($expected, date('Y-m-d H:i:s', strtotime($date))); + } + + /** + * @return mixed[][] + */ + public static function modeProvider() : array + { + return [ + 'bind' => [ + static function (int $interval) : string { + return '?'; + }, + static function (Statement $stmt, int $interval) : void { + $stmt->bindParam(1, $interval, ParameterType::INTEGER); + }, + ], + 'literal' => [ + static function (int $interval) : string { + return sprintf('%d', $interval); + }, + static function (Statement $stmt, int $interval) : void { + }, + ], + 'expression' => [ + static function (int $interval) : string { + return sprintf('(0 + %d)', $interval); + }, + static function (Statement $stmt, int $interval) : void { + }, + ], + ]; } public function testSqliteDateArithmeticWithDynamicInterval() : void @@ -654,11 +930,13 @@ public function testLocateExpression() : void $sql .= $platform->getLocateExpression("'foo'", 'test_string') . ' AS locate5, '; $sql .= $platform->getLocateExpression("'barfoobaz'", 'test_string') . ' AS locate6, '; $sql .= $platform->getLocateExpression("'bar'", 'test_string') . ' AS locate7, '; - $sql .= $platform->getLocateExpression('test_string', "'oo'", 2) . ' AS locate8, '; - $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) . ' AS locate9 '; + $sql .= $platform->getLocateExpression('test_string', "'oo'", '2') . ' AS locate8, '; + $sql .= $platform->getLocateExpression('test_string', "'oo'", '3') . ' AS locate9 '; $sql .= 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); + assert(is_array($row)); + $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(2, $row['locate1']); @@ -672,6 +950,47 @@ public function testLocateExpression() : void self::assertEquals(0, $row['locate9']); } + /** + * @dataProvider substringExpressionProvider + */ + public function testSubstringExpression(string $string, string $start, ?string $length, string $expected) : void + { + $platform = $this->connection->getDatabasePlatform(); + + $query = $platform->getDummySelectSQL( + $platform->getSubstringExpression($string, $start, $length) + ); + + $this->assertEquals($expected, $this->connection->fetchColumn($query)); + } + + /** + * @return mixed[][] + */ + public static function substringExpressionProvider() : iterable + { + return [ + 'start-no-length' => [ + "'abcdef'", + '3', + null, + 'cdef', + ], + 'start-with-length' => [ + "'abcdef'", + '2', + '4', + 'bcde', + ], + 'expressions' => [ + "'abcdef'", + '1 + 1', + '1 + 1', + 'bc', + ], + ]; + } + public function testQuoteSQLInjection() : void { $sql = 'SELECT * FROM fetch_table WHERE test_string = ' . $this->connection->quote("bar' OR '1'='1"); @@ -704,8 +1023,8 @@ public function testBitComparisonExpressionSupport() : void $sql[] = 'SELECT '; $sql[] = 'test_int, '; $sql[] = 'test_string, '; - $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, '; - $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and '; + $sql[] = $platform->getBitOrComparisonExpression('test_int', '2') . ' AS bit_or, '; + $sql[] = $platform->getBitAndComparisonExpression('test_int', '2') . ' AS bit_and '; $sql[] = 'FROM fetch_table'; $stmt = $this->connection->executeQuery(implode(PHP_EOL, $sql)); @@ -954,8 +1273,9 @@ private function beforeFetchClassTest() : void } /** @var PDOConnection $connection */ - $connection = $this->connection->getWrappedConnection(); - $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); + $connection = $this->connection + ->getWrappedConnection(); + $connection->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php index 3adf3c2bb89..992a9ba691c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php @@ -1,5 +1,7 @@ connection->getParams(); unset($params['dbname']); - $user = $params['user'] ?? null; - $password = $params['password'] ?? null; + $user = $params['user'] ?? ''; + $password = $params['password'] ?? ''; $connection = $this->driver->connect($params, $user, $password); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2DriverTest.php index 4021bb2fff7..4b5f3673613 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2DriverTest.php @@ -1,5 +1,7 @@ connection->prepare('SELECT * FROM SYSIBM.SYSDUMMY1 WHERE \'foo\' = ?'); + assert($stmt instanceof Statement); // unwrap the statement to prevent the wrapper from handling the PHPUnit-originated exception $wrappedStmt = $stmt->getWrappedStatement(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/ConnectionTest.php index 4a3a315f296..75fafe25909 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/ConnectionTest.php @@ -1,5 +1,7 @@ getConnection(['hello' => 'world']); // use local infile } - public function testPing() : void - { - $conn = $this->getConnection([]); - self::assertTrue($conn->ping()); - } - /** * @param mixed[] $driverOptions */ @@ -61,7 +57,7 @@ private function getConnection(array $driverOptions) : MysqliConnection [ 'host' => $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], - 'port' => $GLOBALS['db_port'], + 'port' => (int) $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php index d4bbf9a1df7..ea20af2ed59 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php @@ -1,5 +1,7 @@ markTestSkipped('oci8 only test.'); } - $this->driverConnection = $this->connection->getWrappedConnection(); + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof OCI8Connection); + + $this->driverConnection = $wrappedConnection; } /** @@ -47,6 +53,6 @@ public function testLastInsertIdAcceptsFqn() : void $schema = $this->connection->getDatabase(); $sequence = $platform->getIdentitySequenceName($schema . '.DBAL2595', 'id'); - self::assertSame(1, $this->driverConnection->lastInsertId($sequence)); + self::assertEquals(1, $this->driverConnection->lastInsertId($sequence)); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/StatementTest.php index 8ecbed68082..0a26106a968 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/StatementTest.php @@ -1,5 +1,7 @@ markTestSkipped('PDO is not installed.'); - } - parent::setUp(); - $this->driverConnection = $this->connection->getWrappedConnection(); + $wrappedConnection = $this->connection->getWrappedConnection(); - if ($this->driverConnection instanceof PDOConnection) { - return; + if (! $wrappedConnection instanceof PDOConnection) { + $this->markTestSkipped('PDO connection only test.'); } - $this->markTestSkipped('PDO connection only test.'); + $this->driverConnection = $wrappedConnection; } protected function tearDown() : void @@ -90,7 +90,9 @@ public function testThrowsWrappedExceptionOnPrepare() : void // Emulated prepared statements have to be disabled for this test // so that PDO actually communicates with the database server to check the query. - $this->driverConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->driverConnection + ->getWrappedConnection() + ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->expectException(PDOException::class); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/DriverTest.php index 7f77ea542f9..44392eea5b4 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/DriverTest.php @@ -1,5 +1,7 @@ connection->getParams(); $parameters['application_name'] = 'doctrine'; - $user = $parameters['user'] ?? null; - $password = $parameters['password'] ?? null; + $user = $parameters['user'] ?? ''; + $password = $parameters['password'] ?? ''; $connection = $this->driver->connect($parameters, $user, $password); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgsqlConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgsqlConnectionTest.php index 8336a3900d1..a7bdc75b81c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgsqlConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgsqlConnectionTest.php @@ -1,5 +1,7 @@ markTestSkipped('pdo_sqlite only test.'); } + /** + * {@inheritdoc} + */ + public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void + { + $this->markTestSkipped('SQLite does not support the concept of a database.'); + } + /** * {@inheritdoc} */ @@ -31,4 +41,9 @@ protected function createDriver() : DriverInterface { return new Driver(); } + + protected static function getDatabaseNameForConnectionWithoutDatabaseNameParameter() : ?string + { + return ''; + } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php index d2dfd5925f5..3f738ef5a8e 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php @@ -1,12 +1,16 @@ getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]); - self::assertSame(PDO::CASE_UPPER, $connection->getAttribute(PDO::ATTR_CASE)); + assert($connection instanceof PDOConnection); + + self::assertSame( + PDO::CASE_UPPER, + $connection + ->getWrappedConnection() + ->getAttribute(PDO::ATTR_CASE) + ); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/ConnectionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/ConnectionTest.php index 4de7b7cde03..aaff05b11f2 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/ConnectionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/ConnectionTest.php @@ -1,5 +1,7 @@ isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); - self::assertTrue($prepStmt->execute(), ' Statement non-persistent failed'); + $prepStmt->execute(); } public function testPersistentStatement() : void @@ -51,6 +53,6 @@ public function testPersistentStatement() : void self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); - self::assertTrue($prepStmt->execute(), ' Statement persistent failed'); + $prepStmt->execute(); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/DriverTest.php b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/DriverTest.php index eb9931a43dc..df8657525c5 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/DriverTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/DriverTest.php @@ -1,5 +1,7 @@ connection->getWrappedConnection()->prepare(null); + $stmt = $this->connection->getWrappedConnection()->prepare(''); // it's impossible to prepare the statement without bound variables for SQL Server, // so the preparation happens before the first execution when variables are already in place diff --git a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php index 7f4a8145cfe..0e6989cfcac 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php @@ -1,5 +1,7 @@ expectException(Exception\ReadOnlyException::class); $this->expectExceptionMessage(<<markTestSkipped('Only skipped if platform is not sqlite'); } - if ($this->connection->getDatabasePlatform()->getName() === 'drizzle') { - $this->markTestSkipped('Drizzle does not always support authentication'); - } - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql' && isset($params['password'])) { $this->markTestSkipped('Does not work on Travis'); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/LikeWildcardsEscapingTest.php b/tests/Doctrine/Tests/DBAL/Functional/LikeWildcardsEscapingTest.php index e172816f2af..a7c037bc951 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/LikeWildcardsEscapingTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/LikeWildcardsEscapingTest.php @@ -1,5 +1,7 @@ createMasterSlaveConnectionParams($keepSlave)); + $connection = DriverManager::getConnection($this->createMasterSlaveConnectionParams($keepSlave)); + assert($connection instanceof MasterSlaveConnection); + + return $connection; } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php b/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php index a14f9b17582..65bbd2cbe45 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php @@ -1,5 +1,7 @@ connection->getSchemaManager()->tablesExist('ddc1372_foobar')) { + if ($this->connection->getSchemaManager()->tableExists('ddc1372_foobar')) { return; } try { $table = new Table('ddc1372_foobar'); $table->addColumn('id', 'integer'); - $table->addColumn('foo', 'string'); - $table->addColumn('bar', 'string'); + $table->addColumn('foo', 'string', ['length' => 1]); + $table->addColumn('bar', 'string', ['length' => 1]); $table->setPrimaryKey(['id']); $sm = $this->connection->getSchemaManager(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php index 42b8104a9e7..a077d14c204 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php @@ -1,21 +1,21 @@ markTestSkipped('PDO is not installed'); - } - parent::setUp(); if (! $this->connection->getWrappedConnection() instanceof PDOConnection) { @@ -24,13 +24,13 @@ protected function setUp() : void $table = new Table('stmt_test'); $table->addColumn('id', 'integer'); - $table->addColumn('name', 'string'); + $table->addColumn('name', 'string', ['length' => 8]); $this->connection->getSchemaManager()->dropAndCreateTable($table); } /** * @group legacy - * @expectedDeprecation Using a PDO fetch mode or their combination (%d given) is deprecated and will cause an error in Doctrine 3.0 + * @expectedDeprecation Using a PDO fetch mode or their combination (%d given) is deprecated and will cause an error in Doctrine 3.0. */ public function testPDOSpecificModeIsAccepted() : void { diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest.php new file mode 100644 index 00000000000..14fd1ab5a15 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest.php @@ -0,0 +1,120 @@ +assertColumn(Types::STRING, [], 'Test', ParameterType::STRING); + } + + /** + * @dataProvider string8Provider + */ + public function testVariableLengthStringWithLength(string $value) : void + { + $this->assertColumn(Types::STRING, ['length' => 8], $value, ParameterType::STRING); + } + + /** + * @dataProvider string1Provider + */ + public function testFixedLengthStringNoLength(string $value) : void + { + $this->assertColumn(Types::STRING, ['fixed' => true], $value, ParameterType::STRING); + } + + /** + * @dataProvider string8Provider + */ + public function testFixedLengthStringWithLength(string $value) : void + { + $this->assertColumn(Types::STRING, [ + 'fixed' => true, + 'length' => 8, + ], $value, ParameterType::STRING); + } + + /** + * @return iterable> + */ + public static function string1Provider() : iterable + { + return [ + 'ansi' => ['Z'], + 'unicode' => ['Я'], + ]; + } + + /** + * @return iterable> + */ + public static function string8Provider() : iterable + { + return [ + 'ansi' => ['Doctrine'], + 'unicode' => ['Доктрина'], + ]; + } + + public function testVariableLengthBinaryNoLength() : void + { + $this->assertColumn(Types::BINARY, [], "\x00\x01\x02\x03", ParameterType::BINARY); + } + + public function testVariableLengthBinaryWithLength() : void + { + $this->assertColumn(Types::BINARY, ['length' => 8], "\xCE\xC6\x6B\xDD\x9F\xD8\x07\xB4", ParameterType::BINARY); + } + + public function testFixedLengthBinaryNoLength() : void + { + $this->assertColumn(Types::BINARY, ['fixed' => true], "\xFF", ParameterType::BINARY); + } + + public function testFixedLengthBinaryWithLength() : void + { + $this->assertColumn(Types::BINARY, [ + 'fixed' => true, + 'length' => 8, + ], "\xA0\x0A\x7B\x0E\xA4\x60\x78\xD8", ParameterType::BINARY); + } + + protected function requirePlatform(string $class) : void + { + if ($this->connection->getDatabasePlatform() instanceof $class) { + return; + } + + self::markTestSkipped(sprintf('The test requires %s', $class)); + } + + /** + * @param array $column + */ + protected function assertColumn(string $type, array $column, string $value, int $bindType) : void + { + $table = new Table('column_test'); + $table->addColumn('val', $type, $column); + + $sm = $this->connection->getSchemaManager(); + $sm->dropAndCreateTable($table); + + self::assertSame(1, $this->connection->insert('column_test', ['val' => $value], [$bindType])); + + self::assertSame($value, Type::getType($type)->convertToPHPValue( + $this->connection->fetchColumn('SELECT val FROM column_test'), + $this->connection->getDatabasePlatform() + )); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/IBMDB2.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/IBMDB2.php new file mode 100644 index 00000000000..b30cad56755 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/IBMDB2.php @@ -0,0 +1,28 @@ +requirePlatform(DB2Platform::class); + } + + public function testVariableLengthStringNoLength() : void + { + self::markTestSkipped(); + } + + public function testVariableLengthBinaryNoLength() : void + { + self::markTestSkipped(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/MySQL.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/MySQL.php new file mode 100644 index 00000000000..4663709f343 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/MySQL.php @@ -0,0 +1,28 @@ +requirePlatform(MySqlPlatform::class); + } + + public function testVariableLengthStringNoLength() : void + { + self::markTestSkipped(); + } + + public function testVariableLengthBinaryNoLength() : void + { + self::markTestSkipped(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/Oracle.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/Oracle.php new file mode 100644 index 00000000000..99c691f09d2 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/Oracle.php @@ -0,0 +1,33 @@ +requirePlatform(OraclePlatform::class); + } + + public function testVariableLengthStringNoLength() : void + { + self::markTestSkipped(); + } + + public function testVariableLengthBinaryNoLength() : void + { + self::markTestSkipped(); + } + + public function testFixedLengthBinaryNoLength() : void + { + self::markTestSkipped(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/PostgreSQL.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/PostgreSQL.php new file mode 100644 index 00000000000..b6997a45479 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/PostgreSQL.php @@ -0,0 +1,18 @@ +requirePlatform(PostgreSqlPlatform::class); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLServer.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLServer.php new file mode 100644 index 00000000000..0ca863eb788 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLServer.php @@ -0,0 +1,28 @@ +requirePlatform(SQLServerPlatform::class); + } + + public function testVariableLengthStringNoLength() : void + { + self::markTestSkipped(); + } + + public function testVariableLengthBinaryNoLength() : void + { + self::markTestSkipped(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLite.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLite.php new file mode 100644 index 00000000000..79f3b13dbe5 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/ColumnTest/SQLite.php @@ -0,0 +1,18 @@ +requirePlatform(SqlitePlatform::class); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Platform/DateExpressionTest.php b/tests/Doctrine/Tests/DBAL/Functional/Platform/DateExpressionTest.php index 5c1789e192d..b82cf0869c0 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Platform/DateExpressionTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Platform/DateExpressionTest.php @@ -1,5 +1,7 @@ portableConnection = $this->getPortableConnection(); + } + protected function tearDown() : void { - if ($this->portableConnection) { - $this->portableConnection->close(); - } + $this->portableConnection->close(); parent::tearDown(); } @@ -33,53 +39,62 @@ private function getPortableConnection( int $portabilityMode = ConnectionPortability::PORTABILITY_ALL, int $case = ColumnCase::LOWER ) : Connection { - if (! $this->portableConnection) { - $params = $this->connection->getParams(); - - $params['wrapperClass'] = ConnectionPortability::class; - $params['portability'] = $portabilityMode; - $params['fetch_case'] = $case; - - $this->portableConnection = DriverManager::getConnection($params, $this->connection->getConfiguration(), $this->connection->getEventManager()); - - try { - $table = new Table('portability_table'); - $table->addColumn('Test_Int', 'integer'); - $table->addColumn('Test_String', 'string', ['fixed' => true, 'length' => 32]); - $table->addColumn('Test_Null', 'string', ['notnull' => false]); - $table->setPrimaryKey(['Test_Int']); - - $sm = $this->portableConnection->getSchemaManager(); - $sm->createTable($table); - - $this->portableConnection->insert('portability_table', ['Test_Int' => 1, 'Test_String' => 'foo', 'Test_Null' => '']); - $this->portableConnection->insert('portability_table', ['Test_Int' => 2, 'Test_String' => 'foo ', 'Test_Null' => null]); - } catch (Throwable $e) { - } - } - - return $this->portableConnection; + $params = $this->connection->getParams(); + + $params['wrapperClass'] = ConnectionPortability::class; + $params['portability'] = $portabilityMode; + $params['fetch_case'] = $case; + + $portableConnection = DriverManager::getConnection($params, $this->connection->getConfiguration(), $this->connection->getEventManager()); + + $table = new Table('portability_table'); + $table->addColumn('Test_Int', 'integer'); + $table->addColumn('Test_String', 'string', [ + 'length' => 8, + 'fixed' => true, + ]); + $table->addColumn('Test_Null', 'string', [ + 'length' => 1, + 'notnull' => false, + ]); + $table->setPrimaryKey(['Test_Int']); + + $sm = $portableConnection->getSchemaManager(); + $sm->dropAndCreateTable($table); + + $portableConnection->insert('portability_table', [ + 'Test_Int' => 1, + 'Test_String' => 'foo', + 'Test_Null' => '', + ]); + $portableConnection->insert('portability_table', [ + 'Test_Int' => 2, + 'Test_String' => 'foo ', + 'Test_Null' => null, + ]); + + return $portableConnection; } public function testFullFetchMode() : void { - $rows = $this->getPortableConnection()->fetchAll('SELECT * FROM portability_table'); + $rows = $this->portableConnection->fetchAll('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); - $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT * FROM portability_table'); $stmt->setFetchMode(FetchMode::ASSOCIATIVE); foreach ($stmt as $row) { $this->assertFetchResultRow($row); } - $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT * FROM portability_table'); while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { $this->assertFetchResultRow($row); } - $stmt = $this->getPortableConnection()->prepare('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->prepare('SELECT * FROM portability_table'); $stmt->execute(); while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { @@ -89,23 +104,22 @@ public function testFullFetchMode() : void public function testConnFetchMode() : void { - $conn = $this->getPortableConnection(); - $conn->setFetchMode(FetchMode::ASSOCIATIVE); + $this->portableConnection->setFetchMode(FetchMode::ASSOCIATIVE); - $rows = $conn->fetchAll('SELECT * FROM portability_table'); + $rows = $this->portableConnection->fetchAll('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); - $stmt = $conn->query('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT * FROM portability_table'); foreach ($stmt as $row) { $this->assertFetchResultRow($row); } - $stmt = $conn->query('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT * FROM portability_table'); while (($row = $stmt->fetch())) { $this->assertFetchResultRow($row); } - $stmt = $conn->prepare('SELECT * FROM portability_table'); + $stmt = $this->portableConnection->prepare('SELECT * FROM portability_table'); $stmt->execute(); while (($row = $stmt->fetch())) { $this->assertFetchResultRow($row); @@ -142,8 +156,7 @@ public function assertFetchResultRow(array $row) : void */ public function testFetchAllColumn(string $field, array $expected) : void { - $conn = $this->getPortableConnection(); - $stmt = $conn->query('SELECT ' . $field . ' FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT ' . $field . ' FROM portability_table'); $column = $stmt->fetchAll(FetchMode::COLUMN); self::assertEquals($expected, $column); @@ -168,8 +181,7 @@ public static function fetchAllColumnProvider() : iterable public function testFetchAllNullColumn() : void { - $conn = $this->getPortableConnection(); - $stmt = $conn->query('SELECT Test_Null FROM portability_table'); + $stmt = $this->portableConnection->query('SELECT Test_Null FROM portability_table'); $column = $stmt->fetchAll(FetchMode::COLUMN); self::assertSame([null, null], $column); diff --git a/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php b/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php index 35ce061b5b9..d83b430880e 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php @@ -1,5 +1,7 @@ > */ + /** @var array> */ private $expectedResult = [['test_int' => 100, 'test_string' => 'foo'], ['test_int' => 200, 'test_string' => 'bar'], ['test_int' => 300, 'test_string' => 'baz']]; /** @var DebugStack */ @@ -33,11 +35,14 @@ protected function setUp() : void $table = new Table('caching'); $table->addColumn('test_int', 'integer'); - $table->addColumn('test_string', 'string', ['notnull' => false]); + $table->addColumn('test_string', 'string', [ + 'length' => 8, + 'notnull' => false, + ]); $table->setPrimaryKey(['test_int']); $sm = $this->connection->getSchemaManager(); - $sm->createTable($table); + $sm->dropAndCreateTable($table); foreach ($this->expectedResult as $row) { $this->connection->insert('caching', $row); @@ -50,13 +55,6 @@ protected function setUp() : void $config->setResultCacheImpl($cache); } - protected function tearDown() : void - { - $this->connection->getSchemaManager()->dropTable('caching'); - - parent::tearDown(); - } - public function testCacheFetchAssoc() : void { $this->assertCacheNonCacheSelectSameFetchModeAreEqual( @@ -178,7 +176,7 @@ public function testFetchAllAndFinishSavesCache() : void } /** - * @param array> $expectedResult + * @param array $expectedResult */ private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedResult, int $fetchMode) : void { diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/ComparatorTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/ComparatorTest.php index 13503e3187b..ad8fd6ed92a 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/ComparatorTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/ComparatorTest.php @@ -39,7 +39,7 @@ public function testDefaultValueComparison(string $type, $value) : void $onlineTable = $this->schemaManager->listTableDetails('default_value'); - self::assertFalse($this->comparator->diffTable($table, $onlineTable)); + self::assertNull($this->comparator->diffTable($table, $onlineTable)); } /** diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php index 330198e9ca9..28707b3b6a0 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php @@ -1,5 +1,7 @@ addColumn($name, 'string', [ + 'length' => 32, 'default' => $default, 'notnull' => false, ]); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php deleted file mode 100644 index 422740476da..00000000000 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php +++ /dev/null @@ -1,48 +0,0 @@ -addColumn('id', 'integer'); - $table->addColumn('column_varbinary', 'binary', []); - $table->addColumn('column_binary', 'binary', ['fixed' => true]); - $table->setPrimaryKey(['id']); - - $this->schemaManager->createTable($table); - - $table = $this->schemaManager->listTableDetails($tableName); - - self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType()); - self::assertFalse($table->getColumn('column_varbinary')->getFixed()); - - self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType()); - self::assertFalse($table->getColumn('column_binary')->getFixed()); - } - - public function testColumnCollation() : void - { - $table = new Table('test_collation'); - $table->addOption('collate', $collation = 'utf8_unicode_ci'); - $table->addColumn('id', 'integer'); - $table->addColumn('text', 'text'); - $table->addColumn('foo', 'text')->setPlatformOption('collation', 'utf8_swedish_ci'); - $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci'); - $this->schemaManager->dropAndCreateTable($table); - - $columns = $this->schemaManager->listTableColumns('test_collation'); - - self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions()); - self::assertEquals('utf8_unicode_ci', $columns['text']->getPlatformOption('collation')); - self::assertEquals('utf8_swedish_ci', $columns['foo']->getPlatformOption('collation')); - self::assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation')); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php index e9a88e52096..9b57b6e9578 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php @@ -1,8 +1,12 @@ setPrimaryKey(['bar_id', 'foo_id']); $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($tableFetched, $tableNew)); + + $diff = $comparator->diffTable($tableFetched, $tableNew); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $table = $this->schemaManager->listTableDetails('switch_primary_key_columns'); $primaryKey = $table->getPrimaryKeyColumns(); @@ -49,29 +59,6 @@ public function testSwitchPrimaryKeyColumns() : void self::assertContains('foo_id', $primaryKey); } - public function testDiffTableBug() : void - { - $schema = new Schema(); - $table = $schema->createTable('diffbug_routing_translations'); - $table->addColumn('id', 'integer'); - $table->addColumn('route', 'string'); - $table->addColumn('locale', 'string'); - $table->addColumn('attribute', 'string'); - $table->addColumn('localized_value', 'string'); - $table->addColumn('original_value', 'string'); - $table->setPrimaryKey(['id']); - $table->addUniqueIndex(['route', 'locale', 'attribute']); - $table->addIndex(['localized_value']); // this is much more selective than the unique index - - $this->schemaManager->createTable($table); - $tableFetched = $this->schemaManager->listTableDetails('diffbug_routing_translations'); - - $comparator = new Comparator(); - $diff = $comparator->diffTable($tableFetched, $table); - - self::assertFalse($diff, 'no changes expected.'); - } - public function testFulltextIndex() : void { $table = new Table('fulltext_index'); @@ -137,7 +124,11 @@ public function testAlterTableAddPrimaryKey() : void $diffTable->dropIndex('idx_id'); $diffTable->setPrimaryKey(['id']); - $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $table = $this->schemaManager->listTableDetails('alter_table_add_pk'); @@ -163,7 +154,11 @@ public function testDropPrimaryKeyWithAutoincrementColumn() : void $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $table = $this->schemaManager->listTableDetails('drop_primary_key'); @@ -201,7 +196,11 @@ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() : v $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($table, $onlineTable)); + $diff = $comparator->diffTable($table, $onlineTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $onlineTable = $this->schemaManager->listTableDetails('text_blob_default_value'); @@ -244,7 +243,11 @@ public function testAlterColumnCharset() : void $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $table = $this->schemaManager->listTableDetails($tableName); @@ -358,7 +361,7 @@ public function testDiffListGuidTableColumn() : void $comparator = new Comparator(); - self::assertFalse( + self::assertNull( $comparator->diffTable($offlineTable, $onlineTable), 'No differences should be detected with the offline vs online schema.' ); @@ -437,7 +440,7 @@ public function testColumnDefaultCurrentTimestamp() : void $comparator = new Comparator(); $diff = $comparator->diffTable($table, $onlineTable); - self::assertFalse($diff, 'Tables should be identical with column defaults.'); + self::assertNull($diff, 'Tables should be identical with column defaults.'); } public function testColumnDefaultsAreValid() : void @@ -449,7 +452,10 @@ public function testColumnDefaultsAreValid() : void $table->addColumn('col_datetime_null', 'datetime', ['notnull' => false, 'default' => null]); $table->addColumn('col_int', 'integer', ['default' => 1]); $table->addColumn('col_neg_int', 'integer', ['default' => -1]); - $table->addColumn('col_string', 'string', ['default' => 'A']); + $table->addColumn('col_string', 'string', [ + 'length' => 1, + 'default' => 'A', + ]); $table->addColumn('col_decimal', 'decimal', ['scale' => 3, 'precision' => 6, 'default' => -2.3]); $table->addColumn('col_date', 'date', ['default' => '2012-12-12']); @@ -512,7 +518,7 @@ public function testColumnDefaultValuesCurrentTimeAndDate() : void $comparator = new Comparator(); $diff = $comparator->diffTable($table, $onlineTable); - self::assertFalse($diff, 'Tables should be identical with column defauts time and date.'); + self::assertNull($diff, 'Tables should be identical with column defauts time and date.'); } public function testEnsureTableOptionsAreReflectedInMetadata() : void @@ -564,4 +570,18 @@ public function testParseNullCreateOptions() : void self::assertEquals([], $table->getOption('create_options')); } + + public function testListTableColumnsThrowsDatabaseRequired() : void + { + $params = TestUtil::getConnectionParams(); + unset($params['dbname']); + + $connection = DriverManager::getConnection($params); + $schemaManager = $connection->getSchemaManager(); + + self::expectException(DatabaseRequired::class); + self::expectExceptionMessage('A database is required for the method: Doctrine\DBAL\Schema\AbstractSchemaManager::listTableColumns'); + + $schemaManager->listTableColumns('users'); + } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php index b2363b639f0..43fead010d4 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php @@ -1,5 +1,7 @@ schemaManager->listTables(); - self::assertHasTable($tables, 'list_tables_test_new_name'); + self::assertHasTable($tables); } public function testListTableWithBinary() : void @@ -51,8 +53,11 @@ public function testListTableWithBinary() : void $table = new Table($tableName); $table->addColumn('id', 'integer'); - $table->addColumn('column_varbinary', 'binary', []); - $table->addColumn('column_binary', 'binary', ['fixed' => true]); + $table->addColumn('column_varbinary', 'binary', ['length' => 32]); + $table->addColumn('column_binary', 'binary', [ + 'length' => 32, + 'fixed' => true, + ]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); @@ -78,7 +83,7 @@ public function testAlterTableColumnNotNull() : void $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); - $table->addColumn('bar', 'string'); + $table->addColumn('bar', 'string', ['length' => 32]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); @@ -93,7 +98,11 @@ public function testAlterTableColumnNotNull() : void $diffTable->changeColumn('foo', ['notnull' => false]); $diffTable->changeColumn('bar', ['length' => 1024]); - $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns($tableName); @@ -232,10 +241,10 @@ public function testListTableColumnsSameTableNamesInDifferentSchemas() : void $this->schemaManager->dropAndCreateTable($table); $otherTable = new Table($table->getName()); - $otherTable->addColumn('id', Types::STRING); + $otherTable->addColumn('id', Types::STRING, ['length' => 32]); TestUtil::getTempConnection()->getSchemaManager()->dropAndCreateTable($otherTable); - $columns = $this->schemaManager->listTableColumns($table->getName(), $this->connection->getUsername()); + $columns = $this->schemaManager->listTableColumns($table->getName(), $this->connection->getDatabase()); self::assertCount(7, $columns); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php index 35326968798..a749da18292 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php @@ -1,5 +1,7 @@ connection) { - return; - } - - $this->connection->getConfiguration()->setFilterSchemaAssetsExpression(null); + $this->connection->getConfiguration()->setSchemaAssetsFilter(null); } /** @@ -106,7 +109,10 @@ public function testAlterTableAutoIncrementAdd() : void $c = new Comparator(); $diff = $c->diffTable($tableFrom, $tableTo); - $sql = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff); + + self::assertNotNull($diff); + + $sql = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff); self::assertEquals([ 'CREATE SEQUENCE autoinc_table_add_id_seq', "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))", @@ -135,6 +141,9 @@ public function testAlterTableAutoIncrementDrop() : void $c = new Comparator(); $diff = $c->diffTable($tableFrom, $tableTo); + + self::assertNotNull($diff); + self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison'); self::assertEquals(['ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT'], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff)); @@ -159,7 +168,7 @@ public function testTableWithSchema() : void $column = $nestedSchemaTable->addColumn('id', 'integer'); $column->setAutoincrement(true); $nestedSchemaTable->setPrimaryKey(['id']); - $nestedSchemaTable->addUnnamedForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']); + $nestedSchemaTable->addForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']); $this->schemaManager->createTable($nestedRelatedTable); $this->schemaManager->createTable($nestedSchemaTable); @@ -212,11 +221,15 @@ public function testFilterSchemaExpression() : void $column = $testTable->addColumn('id', 'integer'); $this->schemaManager->createTable($testTable); - $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_#'); + $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool { + return preg_match('#^dbal204_#', $name) === 1; + }); $names = $this->schemaManager->listTableNames(); self::assertCount(2, $names); - $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_test#'); + $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool { + return preg_match('#^dbal204_test#', $name) === 1; + }); $names = $this->schemaManager->listTableNames(); self::assertCount(1, $names); } @@ -293,7 +306,7 @@ public function testBooleanDefault() : void $c = new Comparator(); $diff = $c->diffTable($table, $databaseTable); - self::assertFalse($diff); + self::assertNull($diff); } public function testListTableWithBinary() : void @@ -332,7 +345,7 @@ public function testListQuotedTable() : void $comparator = new Schema\Comparator(); - self::assertFalse($comparator->diffTable($offlineTable, $onlineTable)); + self::assertNull($comparator->diffTable($offlineTable, $onlineTable)); } public function testListTablesExcludesViews() : void @@ -378,16 +391,13 @@ public function testPartialIndexes() : void $comparator = new Schema\Comparator(); - self::assertFalse($comparator->diffTable($offlineTable, $onlineTable)); + self::assertNull($comparator->diffTable($offlineTable, $onlineTable)); self::assertTrue($onlineTable->hasIndex('simple_partial_index')); self::assertTrue($onlineTable->getIndex('simple_partial_index')->hasOption('where')); self::assertSame('(id IS NULL)', $onlineTable->getIndex('simple_partial_index')->getOption('where')); } - /** - * @dataProvider jsonbColumnTypeProvider - */ - public function testJsonbColumn(string $type) : void + public function testJsonbColumn() : void { if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSQL94Platform) { $this->markTestSkipped('Requires PostgresSQL 9.4+'); @@ -396,24 +406,13 @@ public function testJsonbColumn(string $type) : void } $table = new Schema\Table('test_jsonb'); - $table->addColumn('foo', $type)->setPlatformOption('jsonb', true); + $table->addColumn('foo', Types::JSON)->setPlatformOption('jsonb', true); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_jsonb'); - self::assertSame($type, $columns['foo']->getType()->getName()); - self::assertTrue(true, $columns['foo']->getPlatformOption('jsonb')); - } - - /** - * @return mixed[][] - */ - public function jsonbColumnTypeProvider() : array - { - return [ - [Types::JSON], - [Types::JSON_ARRAY], - ]; + self::assertSame(Types::JSON, $columns['foo']->getType()->getName()); + self::assertTrue($columns['foo']->getPlatformOption('jsonb')); } /** @@ -532,7 +531,7 @@ class MoneyType extends Type /** * {@inheritDoc} */ - public function getName() + public function getName() : string { return 'MyMoney'; } @@ -540,7 +539,7 @@ public function getName() /** * {@inheritDoc} */ - public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string { return 'MyMoney'; } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php index ffb5d6cf5ec..aa5fe608718 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLAnywhereSchemaManagerTest.php @@ -1,5 +1,7 @@ schemaManager->createTable($table); - $diff = new TableDiff('sqlsrv_drop_column', [], [], [new Column('todrop', Type::getType('decimal'))]); + $diff = new TableDiff('sqlsrv_drop_column', [], [], ['todrop' => new Column('todrop', Type::getType('decimal'))]); $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns('sqlsrv_drop_column'); @@ -37,30 +39,42 @@ public function testDropColumnConstraints() : void public function testColumnCollation() : void { $table = new Table($tableName = 'test_collation'); - $column = $table->addColumn($columnName = 'test', 'string'); + $column = $table->addColumn('test', 'string', ['length' => 32]); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); - self::assertTrue($columns[$columnName]->hasPlatformOption('collation')); // SQL Server should report a default collation on the column + self::assertTrue($columns['test']->hasPlatformOption('collation')); // SQL Server should report a default collation on the column $column->setPlatformOption('collation', $collation = 'Icelandic_CS_AS'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); - self::assertEquals($collation, $columns[$columnName]->getPlatformOption('collation')); + self::assertEquals($collation, $columns['test']->getPlatformOption('collation')); } public function testDefaultConstraints() : void { $table = new Table('sqlsrv_default_constraints'); - $table->addColumn('no_default', 'string'); + $table->addColumn('no_default', 'string', ['length' => 32]); $table->addColumn('df_integer', 'integer', ['default' => 666]); - $table->addColumn('df_string_1', 'string', ['default' => 'foobar']); - $table->addColumn('df_string_2', 'string', ['default' => 'Doctrine rocks!!!']); - $table->addColumn('df_string_3', 'string', ['default' => 'another default value']); - $table->addColumn('df_string_4', 'string', ['default' => 'column to rename']); + $table->addColumn('df_string_1', 'string', [ + 'length' => 32, + 'default' => 'foobar', + ]); + $table->addColumn('df_string_2', 'string', [ + 'length' => 32, + 'default' => 'Doctrine rocks!!!', + ]); + $table->addColumn('df_string_3', 'string', [ + 'length' => 32, + 'default' => 'another default value', + ]); + $table->addColumn('df_string_4', 'string', [ + 'length' => 32, + 'default' => 'column to rename', + ]); $table->addColumn('df_boolean', 'boolean', ['default' => true]); $this->schemaManager->createTable($table); @@ -85,9 +99,12 @@ public function testDefaultConstraints() : void ), 'df_string_2' => new ColumnDiff( 'df_string_2', - new Column('df_string_2', Type::getType('string')), + new Column('df_string_2', Type::getType('string'), ['length' => 32]), ['default'], - new Column('df_string_2', Type::getType('string'), ['default' => 'Doctrine rocks!!!']) + new Column('df_string_2', Type::getType('string'), [ + 'length' => 32, + 'default' => 'Doctrine rocks!!!', + ]) ), 'df_string_3' => new ColumnDiff( 'df_string_3', @@ -103,7 +120,7 @@ public function testDefaultConstraints() : void ), ], [ - 'df_string_1' => new Column('df_string_1', Type::getType('string')), + 'df_string_1' => new Column('df_string_1', Type::getType('string'), ['length' => 32]), ], [], [], @@ -162,10 +179,7 @@ public function testColumnComments() : void $table = new Table('sqlsrv_column_comment'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); - $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); - $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); - $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); @@ -177,13 +191,10 @@ public function testColumnComments() : void $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment'); - self::assertCount(12, $columns); + self::assertCount(9, $columns); self::assertNull($columns['id']->getComment()); self::assertNull($columns['comment_null']->getComment()); - self::assertNull($columns['comment_false']->getComment()); self::assertNull($columns['comment_empty_string']->getComment()); - self::assertEquals('0', $columns['comment_integer_0']->getComment()); - self::assertEquals('0', $columns['comment_float_0']->getComment()); self::assertEquals('0', $columns['comment_string_0']->getComment()); self::assertEquals('Doctrine 0wnz you!', $columns['comment']->getComment()); self::assertEquals('Doctrine 0wnz comments for explicitly quoted columns!', $columns['comment_quoted']->getComment()); @@ -195,10 +206,7 @@ public function testColumnComments() : void $tableDiff->fromTable = $table; $tableDiff->addedColumns['added_comment_none'] = new Column('added_comment_none', Type::getType('integer')); $tableDiff->addedColumns['added_comment_null'] = new Column('added_comment_null', Type::getType('integer'), ['comment' => null]); - $tableDiff->addedColumns['added_comment_false'] = new Column('added_comment_false', Type::getType('integer'), ['comment' => false]); $tableDiff->addedColumns['added_comment_empty_string'] = new Column('added_comment_empty_string', Type::getType('integer'), ['comment' => '']); - $tableDiff->addedColumns['added_comment_integer_0'] = new Column('added_comment_integer_0', Type::getType('integer'), ['comment' => 0]); - $tableDiff->addedColumns['added_comment_float_0'] = new Column('added_comment_float_0', Type::getType('integer'), ['comment' => 0.0]); $tableDiff->addedColumns['added_comment_string_0'] = new Column('added_comment_string_0', Type::getType('integer'), ['comment' => '0']); $tableDiff->addedColumns['added_comment'] = new Column('added_comment', Type::getType('integer'), ['comment' => 'Doctrine']); $tableDiff->addedColumns['`added_comment_quoted`'] = new Column('`added_comment_quoted`', Type::getType('integer'), ['comment' => 'rulez']); @@ -206,8 +214,6 @@ public function testColumnComments() : void $tableDiff->addedColumns['added_commented_type'] = new Column('added_commented_type', Type::getType('object')); $tableDiff->addedColumns['added_commented_type_with_comment'] = new Column('added_commented_type_with_comment', Type::getType('array'), ['comment' => '666']); - $tableDiff->renamedColumns['comment_float_0'] = new Column('comment_double_0', Type::getType('decimal'), ['comment' => 'Double for real!']); - // Add comment to non-commented column. $tableDiff->changedColumns['id'] = new ColumnDiff( 'id', @@ -219,17 +225,12 @@ public function testColumnComments() : void // Remove comment from null-commented column. $tableDiff->changedColumns['comment_null'] = new ColumnDiff( 'comment_null', - new Column('comment_null', Type::getType('string')), + new Column('comment_null', Type::getType('string'), ['length' => 255]), ['type'], - new Column('comment_null', Type::getType('integer'), ['comment' => null]) - ); - - // Add comment to false-commented column. - $tableDiff->changedColumns['comment_false'] = new ColumnDiff( - 'comment_false', - new Column('comment_false', Type::getType('integer'), ['comment' => 'false']), - ['comment'], - new Column('comment_false', Type::getType('integer'), ['comment' => false]) + new Column('comment_null', Type::getType('integer'), [ + 'length' => 255, + 'comment' => null, + ]) ); // Change type to custom type from empty string commented column. @@ -240,10 +241,10 @@ public function testColumnComments() : void new Column('comment_empty_string', Type::getType('integer'), ['comment' => '']) ); - // Change comment to false-comment from zero-string commented column. + // Change comment to empty comment from zero-string commented column. $tableDiff->changedColumns['comment_string_0'] = new ColumnDiff( 'comment_string_0', - new Column('comment_string_0', Type::getType('integer'), ['comment' => false]), + new Column('comment_string_0', Type::getType('integer'), ['comment' => '']), ['comment'], new Column('comment_string_0', Type::getType('integer'), ['comment' => '0']) ); @@ -288,17 +289,13 @@ public function testColumnComments() : void new Column('commented_type_with_comment', Type::getType('array'), ['comment' => 'Doctrine array type.']) ); - $tableDiff->removedColumns['comment_integer_0'] = new Column('comment_integer_0', Type::getType('integer'), ['comment' => 0]); - $this->schemaManager->alterTable($tableDiff); $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment'); - self::assertCount(23, $columns); + self::assertCount(18, $columns); self::assertEquals('primary', $columns['id']->getComment()); self::assertNull($columns['comment_null']->getComment()); - self::assertEquals('false', $columns['comment_false']->getComment()); self::assertNull($columns['comment_empty_string']->getComment()); - self::assertEquals('0', $columns['comment_double_0']->getComment()); self::assertNull($columns['comment_string_0']->getComment()); self::assertNull($columns['comment']->getComment()); self::assertEquals('Doctrine array.', $columns['comment_quoted']->getComment()); @@ -307,10 +304,7 @@ public function testColumnComments() : void self::assertNull($columns['commented_type_with_comment']->getComment()); self::assertNull($columns['added_comment_none']->getComment()); self::assertNull($columns['added_comment_null']->getComment()); - self::assertNull($columns['added_comment_false']->getComment()); self::assertNull($columns['added_comment_empty_string']->getComment()); - self::assertEquals('0', $columns['added_comment_integer_0']->getComment()); - self::assertEquals('0', $columns['added_comment_float_0']->getComment()); self::assertEquals('0', $columns['added_comment_string_0']->getComment()); self::assertEquals('Doctrine', $columns['added_comment']->getComment()); self::assertEquals('rulez', $columns['added_comment_quoted']->getComment()); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php index 241662b56d3..28673578433 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -1,10 +1,13 @@ connection->getDriver()->connect($params, $user, $password); @@ -290,54 +297,54 @@ public function testListTableColumns() : void self::assertArrayHasKey('test', $columns); self::assertEquals(1, array_search('test', $columnsKeys)); - self::assertEquals('test', strtolower($columns['test']->getname())); - self::assertInstanceOf(StringType::class, $columns['test']->gettype()); - self::assertEquals(255, $columns['test']->getlength()); - self::assertEquals(false, $columns['test']->getfixed()); - self::assertEquals(false, $columns['test']->getnotnull()); - self::assertEquals('expected default', $columns['test']->getdefault()); + self::assertEquals('test', strtolower($columns['test']->getName())); + self::assertInstanceOf(StringType::class, $columns['test']->getType()); + self::assertEquals(255, $columns['test']->getLength()); + self::assertEquals(false, $columns['test']->getFixed()); + self::assertEquals(false, $columns['test']->getNotnull()); + self::assertEquals('expected default', $columns['test']->getDefault()); self::assertIsArray($columns['test']->getPlatformOptions()); - self::assertEquals('foo', strtolower($columns['foo']->getname())); + self::assertEquals('foo', strtolower($columns['foo']->getName())); self::assertEquals(2, array_search('foo', $columnsKeys)); - self::assertInstanceOf(TextType::class, $columns['foo']->gettype()); - self::assertEquals(false, $columns['foo']->getunsigned()); - self::assertEquals(false, $columns['foo']->getfixed()); - self::assertEquals(true, $columns['foo']->getnotnull()); - self::assertEquals(null, $columns['foo']->getdefault()); + self::assertInstanceOf(TextType::class, $columns['foo']->getType()); + self::assertEquals(false, $columns['foo']->getUnsigned()); + self::assertEquals(false, $columns['foo']->getFixed()); + self::assertEquals(true, $columns['foo']->getNotnull()); + self::assertEquals(null, $columns['foo']->getDefault()); self::assertIsArray($columns['foo']->getPlatformOptions()); - self::assertEquals('bar', strtolower($columns['bar']->getname())); + self::assertEquals('bar', strtolower($columns['bar']->getName())); self::assertEquals(3, array_search('bar', $columnsKeys)); - self::assertInstanceOf(DecimalType::class, $columns['bar']->gettype()); - self::assertEquals(null, $columns['bar']->getlength()); - self::assertEquals(10, $columns['bar']->getprecision()); - self::assertEquals(4, $columns['bar']->getscale()); - self::assertEquals(false, $columns['bar']->getunsigned()); - self::assertEquals(false, $columns['bar']->getfixed()); - self::assertEquals(false, $columns['bar']->getnotnull()); - self::assertEquals(null, $columns['bar']->getdefault()); + self::assertInstanceOf(DecimalType::class, $columns['bar']->getType()); + self::assertEquals(null, $columns['bar']->getLength()); + self::assertEquals(10, $columns['bar']->getPrecision()); + self::assertEquals(4, $columns['bar']->getScale()); + self::assertEquals(false, $columns['bar']->getUnsigned()); + self::assertEquals(false, $columns['bar']->getFixed()); + self::assertEquals(false, $columns['bar']->getNotnull()); + self::assertEquals(null, $columns['bar']->getDefault()); self::assertIsArray($columns['bar']->getPlatformOptions()); - self::assertEquals('baz1', strtolower($columns['baz1']->getname())); + self::assertEquals('baz1', strtolower($columns['baz1']->getName())); self::assertEquals(4, array_search('baz1', $columnsKeys)); - self::assertInstanceOf(DateTimeType::class, $columns['baz1']->gettype()); - self::assertEquals(true, $columns['baz1']->getnotnull()); - self::assertEquals(null, $columns['baz1']->getdefault()); + self::assertInstanceOf(DateTimeType::class, $columns['baz1']->getType()); + self::assertEquals(true, $columns['baz1']->getNotnull()); + self::assertEquals(null, $columns['baz1']->getDefault()); self::assertIsArray($columns['baz1']->getPlatformOptions()); - self::assertEquals('baz2', strtolower($columns['baz2']->getname())); + self::assertEquals('baz2', strtolower($columns['baz2']->getName())); self::assertEquals(5, array_search('baz2', $columnsKeys)); - self::assertContains($columns['baz2']->gettype()->getName(), ['time', 'date', 'datetime']); - self::assertEquals(true, $columns['baz2']->getnotnull()); - self::assertEquals(null, $columns['baz2']->getdefault()); + self::assertContains($columns['baz2']->getType()->getName(), ['time', 'date', 'datetime']); + self::assertEquals(true, $columns['baz2']->getNotnull()); + self::assertEquals(null, $columns['baz2']->getDefault()); self::assertIsArray($columns['baz2']->getPlatformOptions()); - self::assertEquals('baz3', strtolower($columns['baz3']->getname())); + self::assertEquals('baz3', strtolower($columns['baz3']->getName())); self::assertEquals(6, array_search('baz3', $columnsKeys)); - self::assertContains($columns['baz3']->gettype()->getName(), ['time', 'date', 'datetime']); - self::assertEquals(true, $columns['baz3']->getnotnull()); - self::assertEquals(null, $columns['baz3']->getdefault()); + self::assertContains($columns['baz3']->getType()->getName(), ['time', 'date', 'datetime']); + self::assertEquals(true, $columns['baz3']->getNotnull()); + self::assertEquals(null, $columns['baz3']->getDefault()); self::assertIsArray($columns['baz3']->getPlatformOptions()); } @@ -376,6 +383,7 @@ public function testListTableColumnsDispatchEvent() : void ->method('onSchemaColumnDefinition'); $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager(); + assert($oldEventManager instanceof EventManager); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaColumnDefinition], $listenerMock); @@ -404,6 +412,7 @@ public function testListTableIndexesDispatchEvent() : void ->method('onSchemaIndexDefinition'); $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager(); + assert($oldEventManager instanceof EventManager); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaIndexDefinition], $listenerMock); @@ -428,7 +437,7 @@ public function testDiffListTableColumns() : void $comparator = new Comparator(); $diff = $comparator->diffTable($offlineTable, $onlineTable); - self::assertFalse($diff, 'No differences should be detected with the offline vs online schema.'); + self::assertNull($diff, 'No differences should be detected with the offline vs online schema.'); } public function testListTableIndexes() : void @@ -578,9 +587,9 @@ public function testAlterTableScenario() : void self::assertFalse($table->hasColumn('test')); self::assertTrue($table->hasColumn('foo')); - $tableDiff = new TableDiff('alter_table'); - $tableDiff->fromTable = $table; - $tableDiff->addedIndexes[] = new Index('foo_idx', ['foo']); + $tableDiff = new TableDiff('alter_table'); + $tableDiff->fromTable = $table; + $tableDiff->addedIndexes['foo_idx'] = new Index('foo_idx', ['foo']); $this->schemaManager->alterTable($tableDiff); @@ -591,9 +600,9 @@ public function testAlterTableScenario() : void self::assertFalse($table->getIndex('foo_idx')->isPrimary()); self::assertFalse($table->getIndex('foo_idx')->isUnique()); - $tableDiff = new TableDiff('alter_table'); - $tableDiff->fromTable = $table; - $tableDiff->changedIndexes[] = new Index('foo_idx', ['foo', 'foreign_key_test']); + $tableDiff = new TableDiff('alter_table'); + $tableDiff->fromTable = $table; + $tableDiff->changedIndexes['foo_idx'] = new Index('foo_idx', ['foo', 'foreign_key_test']); $this->schemaManager->alterTable($tableDiff); @@ -616,11 +625,11 @@ public function testAlterTableScenario() : void self::assertFalse($table->getIndex('bar_idx')->isPrimary()); self::assertFalse($table->getIndex('bar_idx')->isUnique()); - $tableDiff = new TableDiff('alter_table'); - $tableDiff->fromTable = $table; - $tableDiff->removedIndexes[] = new Index('bar_idx', ['foo', 'foreign_key_test']); - $fk = new ForeignKeyConstraint(['foreign_key_test'], 'alter_table_foreign', ['id']); - $tableDiff->addedForeignKeys[] = $fk; + $tableDiff = new TableDiff('alter_table'); + $tableDiff->fromTable = $table; + $tableDiff->removedIndexes['bar_idx'] = new Index('bar_idx', ['foo', 'foreign_key_test']); + $fk = new ForeignKeyConstraint(['foreign_key_test'], 'alter_table_foreign', ['id']); + $tableDiff->addedForeignKeys[] = $fk; $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); @@ -647,8 +656,8 @@ public function testTableInNamespace() : void } //create schema - $diff = new SchemaDiff(); - $diff->newNamespaces[] = 'testschema'; + $diff = new SchemaDiff(); + $diff->newNamespaces['testschema'] = 'testschema'; foreach ($diff->toSql($this->schemaManager->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); @@ -757,6 +766,8 @@ public function testUpdateSchemaWithForeignKeyRenaming() : void $c = new Comparator(); $tableDiff = $c->diffTable($tableFK, $tableFKNew); + self::assertNotNull($tableDiff); + $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('test_fk_rename'); @@ -799,7 +810,11 @@ public function testRenameIndexUsedInForeignKeyConstraint() : void $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($foreignTable, $foreignTable2)); + $diff = $comparator->diffTable($foreignTable, $foreignTable2); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $foreignTable = $this->schemaManager->listTableDetails('test_rename_index_foreign'); @@ -914,7 +929,10 @@ public function testChangeColumnsTypeWithDefaultValue() : void $table = new Table($tableName); $table->addColumn('col_int', 'smallint', ['default' => 666]); - $table->addColumn('col_string', 'string', ['default' => 'foo']); + $table->addColumn('col_string', 'string', [ + 'length' => 3, + 'default' => 'foo', + ]); $this->schemaManager->dropAndCreateTable($table); @@ -929,9 +947,16 @@ public function testChangeColumnsTypeWithDefaultValue() : void $tableDiff->changedColumns['col_string'] = new ColumnDiff( 'col_string', - new Column('col_string', Type::getType('string'), ['default' => 'foo', 'fixed' => true]), + new Column('col_string', Type::getType('string'), [ + 'length' => 3, + 'fixed' => true, + 'default' => 'foo', + ]), ['fixed'], - new Column('col_string', Type::getType('string'), ['default' => 'foo']) + new Column('col_string', Type::getType('string'), [ + 'length' => 3, + 'default' => 'foo', + ]) ); $this->schemaManager->alterTable($tableDiff); @@ -983,7 +1008,7 @@ protected function createTestTable(string $name = 'test_table', array $data = [] */ protected function getTestTable(string $name, array $options = []) : Table { - $table = new Table($name, [], [], [], false, $options); + $table = new Table($name, [], [], [], [], $options); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id']); @@ -995,7 +1020,7 @@ protected function getTestTable(string $name, array $options = []) : Table protected function getTestCompositeTable(string $name) : Table { - $table = new Table($name, [], [], [], false, []); + $table = new Table($name, [], [], [], [], []); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('other_id', 'integer', ['notnull' => true]); @@ -1011,14 +1036,17 @@ protected function getTestCompositeTable(string $name) : Table protected function assertHasTable(array $tables) : void { $foundTable = false; + foreach ($tables as $table) { self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.'); + if (strtolower($table->getName()) !== 'list_tables_test_new_name') { continue; } $foundTable = true; } + self::assertTrue($foundTable, 'Could not find new table'); } @@ -1056,13 +1084,22 @@ public function testColumnDefaultLifecycle() : void { $table = new Table('col_def_lifecycle'); $table->addColumn('id', 'integer', ['autoincrement' => true]); - $table->addColumn('column1', 'string', ['default' => null]); - $table->addColumn('column2', 'string', ['default' => false]); - $table->addColumn('column3', 'string', ['default' => true]); - $table->addColumn('column4', 'string', ['default' => 0]); - $table->addColumn('column5', 'string', ['default' => '']); - $table->addColumn('column6', 'string', ['default' => 'def']); - $table->addColumn('column7', 'integer', ['default' => 0]); + $table->addColumn('column1', 'string', [ + 'length' => 1, + 'default' => null, + ]); + $table->addColumn('column2', 'string', [ + 'length' => 1, + 'default' => '', + ]); + $table->addColumn('column3', 'string', [ + 'length' => 8, + 'default' => 'default1', + ]); + $table->addColumn('column4', 'integer', [ + 'length' => 1, + 'default' => 0, + ]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); @@ -1072,35 +1109,30 @@ public function testColumnDefaultLifecycle() : void self::assertNull($columns['id']->getDefault()); self::assertNull($columns['column1']->getDefault()); self::assertSame('', $columns['column2']->getDefault()); - self::assertSame('1', $columns['column3']->getDefault()); + self::assertSame('default1', $columns['column3']->getDefault()); self::assertSame('0', $columns['column4']->getDefault()); - self::assertSame('', $columns['column5']->getDefault()); - self::assertSame('def', $columns['column6']->getDefault()); - self::assertSame('0', $columns['column7']->getDefault()); $diffTable = clone $table; - $diffTable->changeColumn('column1', ['default' => false]); + $diffTable->changeColumn('column1', ['default' => '']); $diffTable->changeColumn('column2', ['default' => null]); - $diffTable->changeColumn('column3', ['default' => false]); + $diffTable->changeColumn('column3', ['default' => 'default2']); $diffTable->changeColumn('column4', ['default' => null]); - $diffTable->changeColumn('column5', ['default' => false]); - $diffTable->changeColumn('column6', ['default' => 666]); - $diffTable->changeColumn('column7', ['default' => null]); $comparator = new Comparator(); - $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns('col_def_lifecycle'); self::assertSame('', $columns['column1']->getDefault()); self::assertNull($columns['column2']->getDefault()); - self::assertSame('', $columns['column3']->getDefault()); + self::assertSame('default2', $columns['column3']->getDefault()); self::assertNull($columns['column4']->getDefault()); - self::assertSame('', $columns['column5']->getDefault()); - self::assertSame('666', $columns['column6']->getDefault()); - self::assertNull($columns['column7']->getDefault()); } public function testListTableWithBinary() : void @@ -1109,7 +1141,7 @@ public function testListTableWithBinary() : void $table = new Table($tableName); $table->addColumn('id', 'integer'); - $table->addColumn('column_varbinary', 'binary', []); + $table->addColumn('column_varbinary', 'binary', ['length' => 16]); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); @@ -1143,7 +1175,7 @@ public function testListTableDetailsWithFullQualifiedTableName() : void $table = new Table($primaryTableName); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); - $table->addColumn('bar', 'string'); + $table->addColumn('bar', 'string', ['length' => 32]); $table->addForeignKeyConstraint($foreignTableName, ['foo'], ['id']); $table->addIndex(['bar']); $table->setPrimaryKey(['id']); @@ -1306,129 +1338,6 @@ public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys() : void self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes); } - /** - * @after - */ - public function removeJsonArrayTable() : void - { - if (! $this->schemaManager->tablesExist(['json_array_test'])) { - return; - } - - $this->schemaManager->dropTable('json_array_test'); - } - - /** - * @group 2782 - * @group 6654 - */ - public function testComparatorShouldReturnFalseWhenLegacyJsonArrayColumnHasComment() : void - { - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json_array'); - - $this->schemaManager->createTable($table); - - $comparator = new Comparator(); - $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); - - self::assertFalse($tableDiff); - } - - /** - * @group 2782 - * @group 6654 - */ - public function testComparatorShouldModifyOnlyTheCommentWhenUpdatingFromJsonArrayTypeOnLegacyPlatforms() : void - { - if ($this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { - $this->markTestSkipped('This test is only supported on platforms that do not have native JSON type.'); - } - - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json_array'); - - $this->schemaManager->createTable($table); - - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json'); - - $comparator = new Comparator(); - $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); - - self::assertInstanceOf(TableDiff::class, $tableDiff); - - $changedColumn = $tableDiff->changedColumns['parameters'] ?? $tableDiff->changedColumns['PARAMETERS']; - - self::assertSame(['comment'], $changedColumn->changedProperties); - } - - /** - * @group 2782 - * @group 6654 - */ - public function testComparatorShouldAddCommentToLegacyJsonArrayTypeThatDoesNotHaveIt() : void - { - if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { - $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); - } - - $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON NOT NULL)'); - - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json_array'); - - $comparator = new Comparator(); - $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); - - self::assertInstanceOf(TableDiff::class, $tableDiff); - self::assertSame(['comment'], $tableDiff->changedColumns['parameters']->changedProperties); - } - - /** - * @group 2782 - * @group 6654 - */ - public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayType() : void - { - if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { - $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); - } - - $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); - - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json_array'); - - $comparator = new Comparator(); - $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); - - self::assertInstanceOf(TableDiff::class, $tableDiff); - self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); - } - - /** - * @group 2782 - * @group 6654 - */ - public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayTypeEvenWhenPlatformHasJsonSupport() : void - { - if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { - $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); - } - - $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); - - $table = new Table('json_array_test'); - $table->addColumn('parameters', 'json_array'); - - $comparator = new Comparator(); - $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); - - self::assertInstanceOf(TableDiff::class, $tableDiff); - self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); - } - /** * @group 2782 * @group 6654 @@ -1447,34 +1356,33 @@ public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNo $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_test'), $table); - self::assertFalse($tableDiff); + self::assertNull($tableDiff); } /** * @dataProvider commentsProvider * @group 2596 */ - public function testExtractDoctrineTypeFromComment(string $comment, string $expected, string $currentType) : void + public function testExtractDoctrineTypeFromComment(?string $comment, ?string $expectedType) : void { - $result = $this->schemaManager->extractDoctrineTypeFromComment($comment, $currentType); + $re = new ReflectionMethod($this->schemaManager, 'extractDoctrineTypeFromComment'); + $re->setAccessible(true); - self::assertSame($expected, $result); + self::assertSame($expectedType, $re->invokeArgs($this->schemaManager, [&$comment])); } /** - * @return string[][] + * @return mixed[][] */ - public function commentsProvider() : array + public static function commentsProvider() : iterable { - $currentType = 'current type'; - return [ - 'invalid custom type comments' => ['should.return.current.type', $currentType, $currentType], - 'valid doctrine type' => ['(DC2Type:guid)', 'guid', $currentType], - 'valid with dots' => ['(DC2Type:type.should.return)', 'type.should.return', $currentType], - 'valid with namespace' => ['(DC2Type:Namespace\Class)', 'Namespace\Class', $currentType], - 'valid with extra closing bracket' => ['(DC2Type:should.stop)).before)', 'should.stop', $currentType], - 'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop', $currentType], + 'invalid custom type comments' => ['should.return.null', null], + 'valid doctrine type' => ['(DC2Type:guid)', 'guid'], + 'valid with dots' => ['(DC2Type:type.should.return)', 'type.should.return'], + 'valid with namespace' => ['(DC2Type:Namespace\Class)', 'Namespace\Class'], + 'valid with extra closing bracket' => ['(DC2Type:should.stop)).before)', 'should.stop'], + 'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop'], ]; } @@ -1554,13 +1462,15 @@ public function testPrimaryKeyAutoIncrement() : void { $table = new Table('test_pk_auto_increment'); $table->addColumn('id', 'integer', ['autoincrement' => true]); - $table->addColumn('text', 'string'); + $table->addColumn('text', 'string', ['length' => 1]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $this->connection->insert('test_pk_auto_increment', ['text' => '1']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'1\''); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdBeforeDelete = (int) $query->fetchColumn(); @@ -1569,6 +1479,8 @@ public function testPrimaryKeyAutoIncrement() : void $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'2\''); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php index cce8f92f72d..993da8d71a8 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php @@ -1,9 +1,12 @@ connection->getParams(); $params['dbname'] = 'test_drop_database'; - $user = $params['user'] ?? null; - $password = $params['password'] ?? null; + $user = $params['user'] ?? ''; + $password = $params['password'] ?? ''; $connection = $this->connection->getDriver()->connect($params, $user, $password); @@ -98,7 +102,7 @@ public function testListForeignKeysFromExistingDatabase() : void new Schema\ForeignKeyConstraint( ['log'], 'log', - [null], + [''], 'FK_3', ['onUpdate' => 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false] ), @@ -233,9 +237,11 @@ public function testDiffListIntegerAutoincrementTableColumns(string $integerType $diff = $comparator->diffTable($offlineTable, $onlineTable); if ($expectedComparatorDiff) { + self::assertNotNull($diff); + self::assertEmpty($this->schemaManager->getDatabasePlatform()->getAlterTableSQL($diff)); } else { - self::assertFalse($diff); + self::assertNull($diff); } } @@ -272,6 +278,8 @@ public function testPrimaryKeyNoAutoIncrement() : void $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = "2"'); + assert($query instanceof Statement); + $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); diff --git a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php index 392e6d756bc..0a07ff104df 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php @@ -1,8 +1,16 @@ connection->getSchemaManager(); $table = new Table('stmt_longer_results'); - $table->addColumn('param', 'string'); + $table->addColumn('param', 'string', ['length' => 24]); $table->addColumn('val', 'text'); $sm->createTable($table); @@ -238,8 +248,11 @@ public function testFetchFromNonExecutedStatement(callable $fetch, $expected) : public function testCloseCursorOnNonExecutedStatement() : void { + $this->expectNotToPerformAssertions(); + $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); - self::assertTrue($stmt->closeCursor()); + + $stmt->closeCursor(); } /** @@ -247,12 +260,23 @@ public function testCloseCursorOnNonExecutedStatement() : void */ public function testCloseCursorAfterCursorEnd() : void { + $this->expectNotToPerformAssertions(); + $stmt = $this->connection->prepare('SELECT name FROM stmt_test'); $stmt->execute(); $stmt->fetch(); - self::assertTrue($stmt->closeCursor()); + $stmt->closeCursor(); + } + + public function testCloseCursorAfterClosingCursor() : void + { + $this->expectNotToPerformAssertions(); + + $stmt = $this->connection->executeQuery('SELECT name FROM stmt_test'); + $stmt->closeCursor(); + $stmt->closeCursor(); } /** @@ -319,4 +343,68 @@ public function testFetchInColumnMode() : void self::assertEquals(1, $result); } + + public function testExecWithRedundantParameters() : void + { + $driver = $this->connection->getDriver(); + + if ($driver instanceof PDOMySQLDriver + || $driver instanceof PDOOracleDriver + || $driver instanceof PDOSQLSRVDriver + ) { + self::markTestSkipped(sprintf( + 'The underlying implementation of the "%s" driver does not report redundant parameters', + get_class($driver) + )); + } + + if ($driver instanceof DB2Driver) { + self::markTestSkipped('db2_execute() does not report redundant parameters'); + } + + if ($driver instanceof SQLSRVDriver) { + self::markTestSkipped('sqlsrv_prepare() does not report redundant parameters'); + } + + $platform = $this->connection->getDatabasePlatform(); + $query = $platform->getDummySelectSQL(); + $stmt = $this->connection->prepare($query); + + // we want to make sure the exception is thrown by the DBAL code, not by PHPUnit due to a PHP-level error, + // but the wrapper connection wraps everything in a DBAL exception + $this->iniSet('error_reporting', '0'); + + self::expectException(DBALException::class); + $stmt->execute([null]); + } + + /** + * @throws DBALException + * + * @dataProvider nonExistingIndexProvider + */ + public function testFetchColumnNonExistingIndex(int $index) : void + { + if ($this->connection->getWrappedConnection() instanceof PDOConnection) { + $this->markTestSkipped('PDO supports this behavior natively but throws a different exception'); + } + + $platform = $this->connection->getDatabasePlatform(); + $query = $platform->getDummySelectSQL(); + $stmt = $this->connection->query($query); + + self::expectException(DBALException::class); + $stmt->fetchColumn($index); + } + + /** + * @return mixed[][] + */ + public static function nonExistingIndexProvider() : iterable + { + return [ + [1], + [-1], + ]; + } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php b/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php index 9846bf70fa1..34847c6295c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php @@ -1,5 +1,7 @@ connection) { - try { - $tempTable = $this->connection->getDatabasePlatform()->getTemporaryTableName('my_temporary'); - $this->connection->exec($this->connection->getDatabasePlatform()->getDropTemporaryTableSQL($tempTable)); - } catch (Throwable $e) { - } + try { + $tempTable = $this->connection->getDatabasePlatform()->getTemporaryTableName('my_temporary'); + $this->connection->exec($this->connection->getDatabasePlatform()->getDropTemporaryTableSQL($tempTable)); + } catch (Throwable $e) { } parent::tearDown(); @@ -42,8 +42,15 @@ public function testDropTemporaryTableNotAutoCommitTransaction() : void } $platform = $this->connection->getDatabasePlatform(); - $columnDefinitions = ['id' => ['type' => Type::getType('integer'), 'notnull' => true]]; - $tempTable = $platform->getTemporaryTableName('my_temporary'); + $columnDefinitions = [ + [ + 'name' => 'id', + 'type' => Type::getType('integer'), + 'notnull' => true, + ], + ]; + + $tempTable = $platform->getTemporaryTableName('my_temporary'); $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; @@ -77,8 +84,15 @@ public function testCreateTemporaryTableNotAutoCommitTransaction() : void } $platform = $this->connection->getDatabasePlatform(); - $columnDefinitions = ['id' => ['type' => Type::getType('integer'), 'notnull' => true]]; - $tempTable = $platform->getTemporaryTableName('my_temporary'); + $columnDefinitions = [ + [ + 'name' => 'id', + 'type' => Type::getType('integer'), + 'notnull' => true, + ], + ]; + + $tempTable = $platform->getTemporaryTableName('my_temporary'); $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php index a3133635c0d..e7c95b51737 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php @@ -1,5 +1,7 @@ markTestSkipped('OCI8 only test'); } - if ($this->connection->getSchemaManager()->tablesExist('DBAL202')) { + if ($this->connection->getSchemaManager()->tableExists('DBAL202')) { $this->connection->exec('DELETE FROM DBAL202'); } else { $table = new Table('DBAL202'); diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php deleted file mode 100644 index 3ebd3a62f1f..00000000000 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php +++ /dev/null @@ -1,56 +0,0 @@ -connection->getDatabasePlatform()->getName(); - if (in_array($platform, ['mysql', 'sqlite'])) { - return; - } - - $this->markTestSkipped('Currently restricted to MySQL and SQLite.'); - } - - public function testGuidShouldMatchPattern() : void - { - $guid = $this->connection->query($this->getSelectGuidSql())->fetchColumn(); - $pattern = '/[0-9A-F]{8}\-[0-9A-F]{4}\-[0-9A-F]{4}\-[8-9A-B][0-9A-F]{3}\-[0-9A-F]{12}/i'; - self::assertEquals(1, preg_match($pattern, $guid), 'GUID does not match pattern'); - } - - /** - * This test does (of course) not proof that all generated GUIDs are - * random, it should however provide some basic confidence. - */ - public function testGuidShouldBeRandom() : void - { - $statement = $this->connection->prepare($this->getSelectGuidSql()); - $guids = []; - - for ($i = 0; $i < 99; $i++) { - $statement->execute(); - $guid = $statement->fetchColumn(); - self::assertNotContains($guid, $guids, 'Duplicate GUID detected'); - $guids[] = $guid; - } - - $statement->closeCursor(); - } - - private function getSelectGuidSql() : string - { - return 'SELECT ' . $this->connection->getDatabasePlatform()->getGuidExpression(); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL461Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL461Test.php index e1c0927d852..9a0feb2e53a 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL461Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL461Test.php @@ -1,5 +1,7 @@ diffTable($onlineTable, $table); - self::assertFalse($diff); + self::assertNull($diff); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php index 687e6e834a0..f754c494de5 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php @@ -1,11 +1,15 @@ running) { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $pdo = $this->getPDO(); + + $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } parent::tearDown(); @@ -71,7 +77,8 @@ public function testBooleanConversionBoolParamRealPrepares() : void public function testBooleanConversionBoolParamEmulatedPrepares() : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $pdo = $this->getPDO(); + $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -95,7 +102,8 @@ public function testBooleanConversionNullParamEmulatedPrepares( ?bool $statementValue, ?bool $databaseConvertedValue ) : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $pdo = $this->getPDO(); + $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -119,7 +127,8 @@ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInB ?bool $statementValue, bool $databaseConvertedValue ) : void { - $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + $pdo = $this->getPDO(); + $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); @@ -169,4 +178,12 @@ public static function booleanTypeConversionWithoutPdoTypeProvider() : iterable [null, null], ]; } + + private function getPDO() : PDO + { + $wrappedConnection = $this->connection->getWrappedConnection(); + assert($wrappedConnection instanceof PDOConnection); + + return $wrappedConnection->getWrappedConnection(); + } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL752Test.php b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL752Test.php index 47bc1c3e762..7f0a44e1795 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL752Test.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL752Test.php @@ -1,5 +1,7 @@ addColumn('id', 'integer', ['notnull' => false]); - $table->addColumn('test_string', 'string', ['notnull' => false]); + $table->addColumn('test_string', 'string', [ + 'length' => 16, + 'notnull' => false, + ]); $table->addColumn('test_boolean', 'boolean', ['notnull' => false]); $table->addColumn('test_bigint', 'bigint', ['notnull' => false]); $table->addColumn('test_smallint', 'bigint', ['notnull' => false]); @@ -31,7 +36,7 @@ protected function setUp() : void $table->addColumn('test_time', 'time', ['notnull' => false]); $table->addColumn('test_text', 'text', ['notnull' => false]); $table->addColumn('test_array', 'array', ['notnull' => false]); - $table->addColumn('test_json_array', 'json_array', ['notnull' => false]); + $table->addColumn('test_json', 'json', ['notnull' => false]); $table->addColumn('test_object', 'object', ['notnull' => false]); $table->addColumn('test_float', 'float', ['notnull' => false]); $table->addColumn('test_decimal', 'decimal', ['notnull' => false, 'scale' => 2, 'precision' => 10]); @@ -164,7 +169,7 @@ public static function toArrayProvider() : iterable { return [ 'array' => ['array', ['foo' => 'bar']], - 'json_array' => ['json_array', ['foo' => 'bar']], + 'json' => ['json', ['foo' => 'bar']], ]; } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php b/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php index 76236acff0c..676ad97cecf 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php @@ -8,11 +8,10 @@ use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; use Doctrine\Tests\DbalFunctionalTestCase; -use function is_resource; use function random_bytes; use function str_replace; -use function stream_get_contents; class BinaryTest extends DbalFunctionalTestCase { @@ -82,14 +81,6 @@ private function select(string $id) [ParameterType::BINARY] ); - // Currently, `BinaryType` mistakenly converts string values fetched from the DB to a stream. - // It should be the opposite. Streams should be used to represent large objects, not binary - // strings. The confusion comes from the PostgreSQL's type system where binary strings and - // large objects are represented by the same BYTEA type - if (is_resource($value)) { - $value = stream_get_contents($value); - } - - return $value; + return Type::getType('binary')->convertToPHPValue($value, $this->connection->getDatabasePlatform()); } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php index b08751d5ec3..1ac53a524be 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php @@ -1,5 +1,7 @@ addColumn('id', 'integer', ['autoincrement' => true]); - $table->addColumn('test_int', 'integer'); - $table->addColumn('test_string', 'string', ['notnull' => false]); - $table->setPrimaryKey(['id']); - - $this->connection->getSchemaManager()->createTable($table); - } catch (Throwable $e) { - } - $this->connection->executeUpdate('DELETE FROM write_table'); - } + $table = new Table('write_table'); + $table->addColumn('id', 'integer', ['autoincrement' => true]); + $table->addColumn('test_int', 'integer'); + $table->addColumn('test_string', 'string', [ + 'length' => 32, + 'notnull' => false, + ]); + $table->setPrimaryKey(['id']); - /** - * @group DBAL-80 - */ - public function testExecuteUpdateFirstTypeIsNull() : void - { - $sql = 'INSERT INTO write_table (test_string, test_int) VALUES (?, ?)'; - $this->connection->executeUpdate($sql, ['text', 1111], [null, ParameterType::INTEGER]); + $this->connection->getSchemaManager()->dropAndCreateTable($table); - $sql = 'SELECT * FROM write_table WHERE test_string = ? AND test_int = ?'; - self::assertTrue((bool) $this->connection->fetchColumn($sql, ['text', 1111])); + $this->connection->executeUpdate('DELETE FROM write_table'); } public function testExecuteUpdate() : void { - $sql = 'INSERT INTO write_table (test_int) VALUES ( ' . $this->connection->quote(1) . ')'; + $sql = 'INSERT INTO write_table (test_int) VALUES (1)'; $affected = $this->connection->executeUpdate($sql); self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!'); @@ -93,8 +83,8 @@ public function testPrepareWithDbalTypes() : void $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); - $stmt->bindValue(1, 1, Type::getType('integer')); - $stmt->bindValue(2, 'foo', Type::getType('string')); + $stmt->bindValue(1, 1, ParameterType::INTEGER); + $stmt->bindValue(2, 'foo', ParameterType::STRING); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); @@ -105,8 +95,8 @@ public function testPrepareWithDbalTypeNames() : void $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); - $stmt->bindValue(1, 1, 'integer'); - $stmt->bindValue(2, 'foo', 'string'); + $stmt->bindValue(1, 1, ParameterType::INTEGER); + $stmt->bindValue(2, 'foo', ParameterType::STRING); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); @@ -152,7 +142,6 @@ public function testLastInsertId() : void self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 2, 'test_string' => 'bar'])); $num = $this->lastInsertId(); - self::assertNotNull($num, 'LastInsertId() should not be null.'); self::assertGreaterThan(0, $num, 'LastInsertId() should be non-negative number.'); } @@ -188,7 +177,8 @@ public function testLastInsertIdNoSequenceGiven() : void $this->markTestSkipped("Test only works consistently on platforms that support sequences and don't support identity columns."); } - self::assertFalse($this->lastInsertId()); + $this->expectException(DriverException::class); + $this->lastInsertId(); } /** @@ -340,16 +330,14 @@ public function testDeleteWhereIsNull() : void * Returns the ID of the last inserted row or skips the test if the currently used driver * doesn't support this feature * - * @return string|false - * * @throws DriverException */ - private function lastInsertId(?string $name = null) + private function lastInsertId(?string $name = null) : string { try { return $this->connection->lastInsertId($name); } catch (DriverException $e) { - if ($e->getCode() === 'IM001') { + if ($e->getSQLState() === 'IM001') { $this->markTestSkipped($e->getMessage()); } diff --git a/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php b/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php index 26b5a959350..497450e5e36 100644 --- a/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php +++ b/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php @@ -1,5 +1,7 @@ [ 'sql' => 'SELECT column FROM table', - 'params' => null, - 'types' => null, + 'params' => [], + 'types' => [], 'executionMS' => 0, ], ], diff --git a/tests/Doctrine/Tests/DBAL/Performance/TypeConversionPerformanceTest.php b/tests/Doctrine/Tests/DBAL/Performance/TypeConversionPerformanceTest.php index 6a76e90f897..7edd40dacd4 100644 --- a/tests/Doctrine/Tests/DBAL/Performance/TypeConversionPerformanceTest.php +++ b/tests/Doctrine/Tests/DBAL/Performance/TypeConversionPerformanceTest.php @@ -1,5 +1,7 @@ platform->getVarcharTypeDeclarationSQL( - ['length' => 10, 'fixed' => true] - ) - ); - self::assertEquals( - 'VARCHAR(50)', - $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), - 'Variable string declaration is not correct' - ); - self::assertEquals( - 'VARCHAR(255)', - $this->platform->getVarcharTypeDeclarationSQL([]), - 'Long string declaration is not correct' - ); - } - public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); @@ -174,6 +158,8 @@ public function testUniquePrimaryKey() : void $c = new Comparator(); $diff = $c->diffTable($oldTable, $keyTable); + self::assertNotNull($diff); + $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals([ @@ -236,11 +222,11 @@ public function testChangeIndexWithForeignKeys() : void $index = new Index('idx', ['col'], false); $unique = new Index('uniq', ['col'], true); - $diff = new TableDiff('test', [], [], [], [$unique], [], [$index]); + $diff = new TableDiff('test', [], [], [], ['uniq' => $unique], [], ['idx' => $index]); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE test DROP INDEX idx, ADD UNIQUE INDEX uniq (col)'], $sql); - $diff = new TableDiff('test', [], [], [], [$index], [], [$unique]); + $diff = new TableDiff('test', [], [], [], ['idx' => $index], [], ['unique' => $unique]); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE test DROP INDEX uniq, ADD INDEX idx (col)'], $sql); } @@ -350,9 +336,13 @@ public function testAlterTableAddPrimaryKey() : void $diffTable->dropIndex('idx_id'); $diffTable->setPrimaryKey(['id']); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertEquals( ['DROP INDEX idx_id ON alter_table_add_pk', 'ALTER TABLE alter_table_add_pk ADD PRIMARY KEY (id)'], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -372,13 +362,17 @@ public function testAlterPrimaryKeyWithAutoincrementColumn() : void $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['foo']); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertEquals( [ 'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL', 'ALTER TABLE alter_primary_key DROP PRIMARY KEY', 'ALTER TABLE alter_primary_key ADD PRIMARY KEY (foo)', ], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -398,12 +392,16 @@ public function testDropPrimaryKeyWithAutoincrementColumn() : void $diffTable->dropPrimaryKey(); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertEquals( [ 'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL', 'ALTER TABLE drop_primary_key DROP PRIMARY KEY', ], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -424,13 +422,17 @@ public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoinc $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['id']); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertSame( [ 'ALTER TABLE tbl MODIFY id INT NOT NULL', 'ALTER TABLE tbl DROP PRIMARY KEY', 'ALTER TABLE tbl ADD PRIMARY KEY (id)', ], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -451,13 +453,17 @@ public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['id', 'foo']); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertSame( [ 'ALTER TABLE tbl MODIFY id INT NOT NULL', 'ALTER TABLE tbl DROP PRIMARY KEY', 'ALTER TABLE tbl ADD PRIMARY KEY (id, foo)', ], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -477,6 +483,8 @@ public function testAddAutoIncrementPrimaryKey() : void $c = new Comparator(); $diff = $c->diffTable($oldTable, $keyTable); + self::assertNotNull($diff); + $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL, ADD PRIMARY KEY (id)'], $sql); @@ -509,13 +517,17 @@ public function testAlterPrimaryKeyWithNewColumn() : void $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['pkc1', 'pkc2']); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + self::assertSame( [ 'ALTER TABLE yolo DROP PRIMARY KEY', 'ALTER TABLE yolo ADD pkc2 INT NOT NULL', 'ALTER TABLE yolo ADD PRIMARY KEY (pkc1, pkc2)', ], - $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -528,37 +540,18 @@ public function testInitializesDoctrineTypeMappings() : void self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary')); } - protected function getBinaryMaxLength() : int - { - return 65535; - } - - public function testReturnsBinaryTypeDeclarationSQL() : void + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void { - self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('VARBINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65535])); + $this->expectException(ColumnLengthRequired::class); - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65535])); + parent::testGetVariableLengthStringTypeDeclarationSQLNoLength(); } - /** - * @group legacy - * @expectedDeprecation Binary field length 65536 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - * @expectedDeprecation Binary field length 16777215 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - * @expectedDeprecation Binary field length 16777216 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void { - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65536])); - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777215])); - self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777216])); + $this->expectException(ColumnLengthRequired::class); - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65536])); - self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777215])); - self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777216])); + parent::testGetVariableLengthBinaryTypeDeclarationSQLNoLength(); } public function testDoesNotPropagateForeignKeyCreationForNonSupportingEngines() : void @@ -720,7 +713,11 @@ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() : v $comparator = new Comparator(); - self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))); + $diff = $comparator->diffTable($table, $diffTable); + + self::assertNotNull($diff); + + self::assertEmpty($this->platform->getAlterTableSQL($diff)); } /** @@ -987,8 +984,8 @@ public function testColumnCollationDeclarationSQL() : void public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); - $table->addColumn('no_collation', 'string'); - $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'ascii_general_ci'); + $table->addColumn('no_collation', 'string', ['length' => 255]); + $table->addColumn('column_collation', 'string', ['length' => 255])->setPlatformOption('collation', 'ascii_general_ci'); self::assertSame( ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE ascii_general_ci) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'], diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php index 0c44d42a7b4..79db6259a0a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php @@ -1,5 +1,7 @@ $where]); - $uniqueIndex = new Index('name', ['test', 'test2'], true, false, [], ['where' => $where]); + $where = 'test IS NULL AND test2 IS NOT NULL'; + $indexDef = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]); + $uniqueConstraint = new UniqueConstraint('name', ['test', 'test2'], [], []); $expected = ' WHERE ' . $where; @@ -230,24 +233,23 @@ public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() $actuals[] = $this->platform->getIndexDeclarationSQL('name', $indexDef); } - $actuals[] = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueIndex); - $actuals[] = $this->platform->getCreateIndexSQL($indexDef, 'table'); + $uniqueConstraintSQL = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueConstraint); + $indexSQL = $this->platform->getCreateIndexSQL($indexDef, 'table'); - foreach ($actuals as $actual) { - if ($this->platform->supportsPartialIndexes()) { - self::assertStringEndsWith($expected, $actual, 'WHERE clause should be present'); - } else { - self::assertStringEndsNotWith($expected, $actual, 'WHERE clause should NOT be present'); - } + $this->assertStringEndsNotWith($expected, $uniqueConstraintSQL, 'WHERE clause should NOT be present'); + if ($this->platform->supportsPartialIndexes()) { + self::assertStringEndsWith($expected, $indexSQL, 'WHERE clause should be present'); + } else { + self::assertStringEndsNotWith($expected, $indexSQL, 'WHERE clause should NOT be present'); } } public function testGeneratesForeignKeyCreationSql() : void { - $fk = new ForeignKeyConstraint(['fk_name_id'], 'other_table', ['id'], ''); + $fk = new ForeignKeyConstraint(['fk_name_id'], 'other_table', ['id']); $sql = $this->platform->getCreateForeignKeySQL($fk, 'test'); - self::assertEquals($sql, $this->getGenerateForeignKeySql()); + self::assertEquals($this->getGenerateForeignKeySql(), $sql); } abstract public function getGenerateForeignKeySql() : string; @@ -289,8 +291,8 @@ protected function getBitAndComparisonExpressionSql(string $value1, string $valu */ public function testGeneratesBitAndComparisonExpressionSql() : void { - $sql = $this->platform->getBitAndComparisonExpression(2, 4); - self::assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql); + $sql = $this->platform->getBitAndComparisonExpression('2', '4'); + self::assertEquals($this->getBitAndComparisonExpressionSql('2', '4'), $sql); } protected function getBitOrComparisonExpressionSql(string $value1, string $value2) : string @@ -303,8 +305,8 @@ protected function getBitOrComparisonExpressionSql(string $value1, string $value */ public function testGeneratesBitOrComparisonExpressionSql() : void { - $sql = $this->platform->getBitOrComparisonExpression(2, 4); - self::assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql); + $sql = $this->platform->getBitOrComparisonExpression('2', '4'); + self::assertEquals($this->getBitOrComparisonExpressionSql('2', '4'), $sql); } public function getGenerateConstraintUniqueIndexSql() : string @@ -343,20 +345,24 @@ public function testGeneratesTableAlterationSql() : void $table->addColumn('bloo', 'boolean'); $table->setPrimaryKey(['id']); - $tableDiff = new TableDiff('mytable'); - $tableDiff->fromTable = $table; - $tableDiff->newName = 'userlist'; - $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['notnull' => false]); - $tableDiff->removedColumns['foo'] = new Column('foo', Type::getType('integer')); - $tableDiff->changedColumns['bar'] = new ColumnDiff( + $tableDiff = new TableDiff('mytable'); + $tableDiff->fromTable = $table; + $tableDiff->newName = 'userlist'; + $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['notnull' => false]); + $tableDiff->removedColumns['foo'] = new Column('foo', Type::getType('integer')); + $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column( 'baz', Type::getType('string'), - ['default' => 'def'] + [ + 'length' => 255, + 'default' => 'def', + ] ), ['type', 'notnull', 'default'] ); + $tableDiff->changedColumns['bloo'] = new ColumnDiff( 'bloo', new Column( @@ -471,14 +477,9 @@ public function testGetAlterTableSqlDispatchEvent() : void $tableDiff->removedColumns['removed'] = new Column('removed', Type::getType('integer'), []); $tableDiff->changedColumns['changed'] = new ColumnDiff( 'changed', - new Column( - 'changed2', - Type::getType('string'), - [] - ), - [] + new Column('changed2', Type::getType('string'), ['length' => 255]) ); - $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer'), []); + $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer')); $this->platform->getAlterTableSQL($tableDiff); } @@ -504,19 +505,15 @@ public function testAlterTableColumnComments() : void $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']); $tableDiff->changedColumns['foo'] = new ColumnDiff( 'foo', - new Column( - 'foo', - Type::getType('string') - ), + new Column('foo', Type::getType('string'), ['length' => 255]), ['comment'] ); $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', - new Column( - 'baz', - Type::getType('string'), - ['comment' => 'B comment'] - ), + new Column('baz', Type::getType('string'), [ + 'length' => 255, + 'comment' => 'B comment', + ]), ['comment'] ); @@ -638,7 +635,7 @@ public function testKeywordList() : void public function testQuotedColumnInPrimaryKeyPropagation() : void { $table = new Table('`quoted`'); - $table->addColumn('create', 'string'); + $table->addColumn('create', 'string', ['length' => 255]); $table->setPrimaryKey(['create']); $sql = $this->platform->getCreateTableSQL($table); @@ -671,7 +668,7 @@ abstract protected function getQuotedColumnInForeignKeySQL() : array; public function testQuotedColumnInIndexPropagation() : void { $table = new Table('`quoted`'); - $table->addColumn('create', 'string'); + $table->addColumn('create', 'string', ['length' => 255]); $table->addIndex(['create']); $sql = $this->platform->getCreateTableSQL($table); @@ -681,7 +678,7 @@ public function testQuotedColumnInIndexPropagation() : void public function testQuotedNameInIndexSQL() : void { $table = new Table('test'); - $table->addColumn('column1', 'string'); + $table->addColumn('column1', 'string', ['length' => 255]); $table->addIndex(['column1'], '`key`'); $sql = $this->platform->getCreateTableSQL($table); @@ -694,9 +691,9 @@ public function testQuotedNameInIndexSQL() : void public function testQuotedColumnInForeignKeyPropagation() : void { $table = new Table('`quoted`'); - $table->addColumn('create', 'string'); - $table->addColumn('foo', 'string'); - $table->addColumn('`bar`', 'string'); + $table->addColumn('create', 'string', ['length' => 255]); + $table->addColumn('foo', 'string', ['length' => 255]); + $table->addColumn('`bar`', 'string', ['length' => 255]); // Foreign table with reserved keyword as name (needs quotation). $foreignTable = new Table('foreign'); @@ -731,11 +728,11 @@ public function testQuotedColumnInForeignKeyPropagation() : void */ public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : void { - $index = new Index('select', ['foo'], true); + $constraint = new UniqueConstraint('select', ['foo'], [], []); self::assertSame( $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(), - $this->platform->getUniqueConstraintDeclarationSQL('select', $index) + $this->platform->getUniqueConstraintDeclarationSQL('select', $constraint) ); } @@ -806,7 +803,8 @@ public function testAlterTableChangeQuotedColumn() : void 'select', new Column( 'select', - Type::getType('string') + Type::getType('string'), + ['length' => 255] ), ['type'] ); @@ -835,36 +833,114 @@ public function testReturnsIdentitySequenceName() : void $this->platform->getIdentitySequenceName('mytable', 'mycolumn'); } - public function testReturnsBinaryDefaultLength() : void + public function testGetFixedLengthStringTypeDeclarationSQLNoLength() : void { - self::assertSame($this->getBinaryDefaultLength(), $this->platform->getBinaryDefaultLength()); + self::assertSame( + $this->getExpectedFixedLengthStringTypeDeclarationSQLNoLength(), + $this->platform->getStringTypeDeclarationSQL(['fixed' => true]) + ); } - protected function getBinaryDefaultLength() : int + protected function getExpectedFixedLengthStringTypeDeclarationSQLNoLength() : string { - return 255; + return 'CHAR'; } - public function testReturnsBinaryMaxLength() : void + public function testGetFixedLengthStringTypeDeclarationSQLWithLength() : void { - self::assertSame($this->getBinaryMaxLength(), $this->platform->getBinaryMaxLength()); + self::assertSame( + $this->getExpectedFixedLengthStringTypeDeclarationSQLWithLength(), + $this->platform->getStringTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 16, + ]) + ); } - protected function getBinaryMaxLength() : int + protected function getExpectedFixedLengthStringTypeDeclarationSQLWithLength() : string { - return 4000; + return 'CHAR(16)'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void { - $this->expectException(DBALException::class); + self::assertSame( + $this->getExpectedVariableLengthStringTypeDeclarationSQLNoLength(), + $this->platform->getStringTypeDeclarationSQL([]) + ); + } + + protected function getExpectedVariableLengthStringTypeDeclarationSQLNoLength() : string + { + return 'VARCHAR'; + } + + public function testGetVariableLengthStringTypeDeclarationSQLWithLength() : void + { + self::assertSame( + $this->getExpectedVariableLengthStringTypeDeclarationSQLWithLength(), + $this->platform->getStringTypeDeclarationSQL(['length' => 16]) + ); + } + + protected function getExpectedVariableLengthStringTypeDeclarationSQLWithLength() : string + { + return 'VARCHAR(16)'; + } - $this->platform->getBinaryTypeDeclarationSQL([]); + public function testGetFixedLengthBinaryTypeDeclarationSQLNoLength() : void + { + self::assertSame( + $this->getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength(), + $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]) + ); } - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void + public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string { - $this->markTestSkipped('Not applicable to the platform'); + return 'BINARY'; + } + + public function testGetFixedLengthBinaryTypeDeclarationSQLWithLength() : void + { + self::assertSame( + $this->getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength(), + $this->platform->getBinaryTypeDeclarationSQL([ + 'fixed' => true, + 'length' => 16, + ]) + ); + } + + public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string + { + return 'BINARY(16)'; + } + + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void + { + self::assertSame( + $this->getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength(), + $this->platform->getBinaryTypeDeclarationSQL([]) + ); + } + + public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string + { + return 'VARBINARY'; + } + + public function testGetVariableLengthBinaryTypeDeclarationSQLWithLength() : void + { + self::assertSame( + $this->getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength(), + $this->platform->getBinaryTypeDeclarationSQL(['length' => 16]) + ); + } + + public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string + { + return 'VARBINARY(16)'; } /** @@ -883,7 +959,7 @@ public function testReturnsJsonTypeDeclarationSQL() : void $column = [ 'length' => 666, 'notnull' => true, - 'type' => Type::getType('json_array'), + 'type' => Type::getType('json'), ]; self::assertSame( @@ -994,9 +1070,13 @@ public function testQuotesAlterTableRenameColumn() : void $comparator = new Comparator(); + $diff = $comparator->diffTable($fromTable, $toTable); + + self::assertNotNull($diff); + self::assertEquals( $this->getQuotedAlterTableRenameColumnSQL(), - $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -1036,9 +1116,13 @@ public function testQuotesAlterTableChangeColumnLength() : void $comparator = new Comparator(); + $diff = $comparator->diffTable($fromTable, $toTable); + + self::assertNotNull($diff); + self::assertEquals( $this->getQuotedAlterTableChangeColumnLengthSQL(), - $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable)) + $this->platform->getAlterTableSQL($diff) ); } @@ -1300,7 +1384,7 @@ public function testThrowsExceptionOnGeneratingInlineColumnCommentSQLIfUnsupport } $this->expectException(DBALException::class); - $this->expectExceptionMessage("Operation 'Doctrine\\DBAL\\Platforms\\AbstractPlatform::getInlineColumnCommentSQL' is not supported by platform."); + $this->expectExceptionMessage('Operation "Doctrine\\DBAL\\Platforms\\AbstractPlatform::getInlineColumnCommentSQL" is not supported by platform.'); $this->expectExceptionCode(0); $this->platform->getInlineColumnCommentSQL('unsupported'); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php index 44c28018849..0ff3c5727cf 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php @@ -1,7 +1,10 @@ true] + ['deferred' => true] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED', @@ -140,8 +147,8 @@ public function testGeneratesSqlSnippets() : void self::assertEquals('SIMILAR TO', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct'); self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); - self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); - self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', 1, 5), 'Substring expression with length is not correct'); + self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct'); + self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', '1', '5'), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() : void @@ -258,26 +265,6 @@ public function testGeneratesTypeDeclarationForIntegers() : void ); } - public function testGeneratesTypeDeclarationForStrings() : void - { - self::assertEquals( - 'CHAR(10)', - $this->platform->getVarcharTypeDeclarationSQL( - ['length' => 10, 'fixed' => true] - ) - ); - self::assertEquals( - 'VARCHAR(50)', - $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), - 'Variable string declaration is not correct' - ); - self::assertEquals( - 'VARCHAR(255)', - $this->platform->getVarcharTypeDeclarationSQL([]), - 'Long string declaration is not correct' - ); - } - public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; @@ -424,20 +411,16 @@ protected function getQuotedColumnInForeignKeySQL() : array } /** - * @param string|bool $databaseValue - * * @group DBAL-457 * @dataProvider pgBooleanProvider */ public function testConvertBooleanAsLiteralStrings( - $databaseValue, + string $databaseValue, string $preparedStatementValue, - ?int $integerValue, - ?bool $booleanValue + int $integerValue, + bool $booleanValue ) : void { - $platform = $this->createPlatform(); - - self::assertEquals($preparedStatementValue, $platform->convertBooleans($databaseValue)); + self::assertEquals($preparedStatementValue, $this->platform->convertBooleans($databaseValue)); } /** @@ -445,31 +428,26 @@ public function testConvertBooleanAsLiteralStrings( */ public function testConvertBooleanAsLiteralIntegers() : void { - $platform = $this->createPlatform(); - $platform->setUseBooleanTrueFalseStrings(false); + $this->platform->setUseBooleanTrueFalseStrings(false); - self::assertEquals(1, $platform->convertBooleans(true)); - self::assertEquals(1, $platform->convertBooleans('1')); + self::assertEquals(1, $this->platform->convertBooleans(true)); + self::assertEquals(1, $this->platform->convertBooleans('1')); - self::assertEquals(0, $platform->convertBooleans(false)); - self::assertEquals(0, $platform->convertBooleans('0')); + self::assertEquals(0, $this->platform->convertBooleans(false)); + self::assertEquals(0, $this->platform->convertBooleans('0')); } /** - * @param string|bool $databaseValue - * * @group DBAL-630 * @dataProvider pgBooleanProvider */ public function testConvertBooleanAsDatabaseValueStrings( - $databaseValue, + string $databaseValue, string $preparedStatementValue, - ?int $integerValue, - ?bool $booleanValue + int $integerValue, + bool $booleanValue ) : void { - $platform = $this->createPlatform(); - - self::assertSame($integerValue, $platform->convertBooleansToDatabaseValue($booleanValue)); + self::assertSame($integerValue, $this->platform->convertBooleansToDatabaseValue($booleanValue)); } /** @@ -477,33 +455,26 @@ public function testConvertBooleanAsDatabaseValueStrings( */ public function testConvertBooleanAsDatabaseValueIntegers() : void { - $platform = $this->createPlatform(); - $platform->setUseBooleanTrueFalseStrings(false); + $this->platform->setUseBooleanTrueFalseStrings(false); - self::assertSame(1, $platform->convertBooleansToDatabaseValue(true)); - self::assertSame(0, $platform->convertBooleansToDatabaseValue(false)); + self::assertSame(1, $this->platform->convertBooleansToDatabaseValue(true)); + self::assertSame(0, $this->platform->convertBooleansToDatabaseValue(false)); } /** - * @param string|bool $databaseValue - * * @dataProvider pgBooleanProvider */ - public function testConvertFromBoolean($databaseValue, string $prepareStatementValue, ?int $integerValue, ?bool $booleanValue) : void + public function testConvertFromBoolean(string $databaseValue, string $prepareStatementValue, int $integerValue, bool $booleanValue) : void { - $platform = $this->createPlatform(); - - self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue)); + self::assertSame($booleanValue, $this->platform->convertFromBoolean($databaseValue)); } public function testThrowsExceptionWithInvalidBooleanLiteral() : void { - $platform = $this->createPlatform(); - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage("Unrecognized boolean literal 'my-bool'"); + $this->expectExceptionMessage('Unrecognized boolean literal, my-bool given.'); - $platform->convertBooleansToDatabaseValue('my-bool'); + $this->platform->convertBooleansToDatabaseValue('my-bool'); } public function testGetCreateSchemaSQL() : void @@ -583,11 +554,13 @@ public function testDroppingConstraintsBeforeColumns() : void $oldTable = clone $newTable; $oldTable->addColumn('parent_id', 'integer'); - $oldTable->addUnnamedForeignKeyConstraint('mytable', ['parent_id'], ['id']); + $oldTable->addForeignKeyConstraint('mytable', ['parent_id'], ['id']); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($oldTable, $newTable); + self::assertNotNull($tableDiff); + $sql = $this->platform->getAlterTableSQL($tableDiff); $expectedSql = [ @@ -635,25 +608,24 @@ public static function dataCreateSequenceWithCache() : iterable ]; } - protected function getBinaryDefaultLength() : int + public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string { - return 0; + return 'BYTEA'; } - protected function getBinaryMaxLength() : int + public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string { - return 0; + return 'BYTEA'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string { - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999])); + return 'BYTEA'; + } - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999])); + public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string + { + return 'BYTEA'; } public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void @@ -670,30 +642,42 @@ public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : v $comparator = new Comparator(); + $diff = $comparator->diffTable($table1, $table2); + + self::assertNotNull($diff); + // VARBINARY -> BINARY // BINARY -> VARBINARY // BLOB -> VARBINARY - self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); + self::assertEmpty($this->platform->getAlterTableSQL($diff)); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'binary', ['length' => 42]); $table2->addColumn('column_binary', 'blob'); $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]); + $diff = $comparator->diffTable($table1, $table2); + + self::assertNotNull($diff); + // VARBINARY -> VARBINARY with changed length // BINARY -> BLOB // BLOB -> BINARY - self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); + self::assertEmpty($this->platform->getAlterTableSQL($diff)); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'blob'); $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]); $table2->addColumn('column_blob', 'blob'); + $diff = $comparator->diffTable($table1, $table2); + + self::assertNotNull($diff); + // VARBINARY -> BLOB // BINARY -> BINARY with changed length // BLOB -> BLOB - self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); + self::assertEmpty($this->platform->getAlterTableSQL($diff)); } /** @@ -728,7 +712,6 @@ public static function pgBooleanProvider() : iterable { return [ // Database value, prepared statement value, boolean integer value, boolean value. - [true, 'true', 1, true], ['t', 'true', 1, true], ['true', 'true', 1, true], ['y', 'true', 1, true], @@ -736,15 +719,12 @@ public static function pgBooleanProvider() : iterable ['on', 'true', 1, true], ['1', 'true', 1, true], - [false, 'false', 0, false], ['f', 'false', 0, false], ['false', 'false', 0, false], [ 'n', 'false', 0, false], ['no', 'false', 0, false], ['off', 'false', 0, false], ['0', 'false', 0, false], - - [null, 'NULL', null, null], ]; } @@ -809,14 +789,6 @@ protected function getQuotesDropForeignKeySQL() : string return 'ALTER TABLE "table" DROP CONSTRAINT "select"'; } - public function testGetNullCommentOnColumnSQL() : void - { - self::assertEquals( - 'COMMENT ON COLUMN mytable.id IS NULL', - $this->platform->getCommentOnColumnSQL('mytable', 'id', null) - ); - } - /** * @group DBAL-423 */ @@ -961,6 +933,8 @@ public function testInitializesTsvectorTypeMapping() : void */ public function testReturnsDisallowDatabaseConnectionsSQL() : void { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertSame( "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'", $this->platform->getDisallowDatabaseConnectionsSQL('foo') @@ -972,6 +946,8 @@ public function testReturnsDisallowDatabaseConnectionsSQL() : void */ public function testReturnsCloseActiveDatabaseConnectionsSQL() : void { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertSame( "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'", $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') @@ -1060,6 +1036,8 @@ public function testQuotesSchemaNameInListTableColumnsSQL() : void */ public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void { + assert($this->platform instanceof PostgreSqlPlatform); + self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\") diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php index 46627bd8cf2..eaddf9e7392 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php @@ -1,8 +1,12 @@ platform->getVarcharTypeDeclarationSQL( - ['length' => 10, 'fixed' => true] - ) - ); - self::assertEquals( - 'NVARCHAR(50)', - $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), - 'Variable string declaration is not correct' - ); - self::assertEquals( - 'NVARCHAR(255)', - $this->platform->getVarcharTypeDeclarationSQL([]), - 'Long string declaration is not correct' - ); self::assertSame('VARCHAR(MAX)', $this->platform->getClobTypeDeclarationSQL([])); self::assertSame( 'VARCHAR(MAX)', @@ -702,24 +691,22 @@ public function testGeneratesCreateTableSQLWithColumnComments() : void $table = new Table('mytable'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); - $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); - $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); - $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']); $table->addColumn('commented_type', 'object'); $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']); - $table->addColumn('comment_with_string_literal_char', 'string', ['comment' => "O'Reilly"]); + $table->addColumn('comment_with_string_literal_char', 'string', [ + 'length' => 255, + 'comment' => "O'Reilly", + ]); $table->setPrimaryKey(['id']); self::assertEquals( [ - 'CREATE TABLE mytable (id INT IDENTITY NOT NULL, comment_null INT NOT NULL, comment_false INT NOT NULL, comment_empty_string INT NOT NULL, comment_integer_0 INT NOT NULL, comment_float_0 INT NOT NULL, comment_string_0 INT NOT NULL, comment INT NOT NULL, [comment_quoted] INT NOT NULL, [create] INT NOT NULL, commented_type VARCHAR(MAX) NOT NULL, commented_type_with_comment VARCHAR(MAX) NOT NULL, comment_with_string_literal_char NVARCHAR(255) NOT NULL, PRIMARY KEY (id))', - "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_integer_0", - "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_float_0", + 'CREATE TABLE mytable (id INT IDENTITY NOT NULL, comment_null INT NOT NULL, comment_empty_string INT NOT NULL, comment_string_0 INT NOT NULL, comment INT NOT NULL, [comment_quoted] INT NOT NULL, [create] INT NOT NULL, commented_type VARCHAR(MAX) NOT NULL, commented_type_with_comment VARCHAR(MAX) NOT NULL, comment_with_string_literal_char NVARCHAR(255) NOT NULL, PRIMARY KEY (id))', "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_string_0", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine 0wnz you!', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine 0wnz comments for explicitly quoted columns!', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [comment_quoted]", @@ -741,36 +728,34 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void $table = new Table('mytable'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); - $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); - $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); - $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']); $table->addColumn('commented_type', 'object'); $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']); - $table->addColumn('comment_with_string_literal_quote_char', 'array', ['comment' => "O'Reilly"]); + $table->addColumn('comment_with_string_literal_quote_char', 'array', [ + 'length' => 255, + 'comment' => "O'Reilly", + ]); $table->setPrimaryKey(['id']); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->addedColumns['added_comment_none'] = new Column('added_comment_none', Type::getType('integer')); $tableDiff->addedColumns['added_comment_null'] = new Column('added_comment_null', Type::getType('integer'), ['comment' => null]); - $tableDiff->addedColumns['added_comment_false'] = new Column('added_comment_false', Type::getType('integer'), ['comment' => false]); $tableDiff->addedColumns['added_comment_empty_string'] = new Column('added_comment_empty_string', Type::getType('integer'), ['comment' => '']); - $tableDiff->addedColumns['added_comment_integer_0'] = new Column('added_comment_integer_0', Type::getType('integer'), ['comment' => 0]); - $tableDiff->addedColumns['added_comment_float_0'] = new Column('added_comment_float_0', Type::getType('integer'), ['comment' => 0.0]); $tableDiff->addedColumns['added_comment_string_0'] = new Column('added_comment_string_0', Type::getType('integer'), ['comment' => '0']); $tableDiff->addedColumns['added_comment'] = new Column('added_comment', Type::getType('integer'), ['comment' => 'Doctrine']); $tableDiff->addedColumns['`added_comment_quoted`'] = new Column('`added_comment_quoted`', Type::getType('integer'), ['comment' => 'rulez']); $tableDiff->addedColumns['select'] = new Column('select', Type::getType('integer'), ['comment' => '666']); $tableDiff->addedColumns['added_commented_type'] = new Column('added_commented_type', Type::getType('object')); $tableDiff->addedColumns['added_commented_type_with_comment'] = new Column('added_commented_type_with_comment', Type::getType('array'), ['comment' => '666']); - $tableDiff->addedColumns['added_comment_with_string_literal_char'] = new Column('added_comment_with_string_literal_char', Type::getType('string'), ['comment' => "''"]); - - $tableDiff->renamedColumns['comment_float_0'] = new Column('comment_double_0', Type::getType('decimal'), ['comment' => 'Double for real!']); + $tableDiff->addedColumns['added_comment_with_string_literal_char'] = new Column('added_comment_with_string_literal_char', Type::getType('string'), [ + 'length' => 255, + 'comment' => "''", + ]); // Add comment to non-commented column. $tableDiff->changedColumns['id'] = new ColumnDiff( @@ -783,19 +768,11 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void // Remove comment from null-commented column. $tableDiff->changedColumns['comment_null'] = new ColumnDiff( 'comment_null', - new Column('comment_null', Type::getType('string')), + new Column('comment_null', Type::getType('string'), ['length' => 255]), ['type'], new Column('comment_null', Type::getType('integer'), ['comment' => null]) ); - // Add comment to false-commented column. - $tableDiff->changedColumns['comment_false'] = new ColumnDiff( - 'comment_false', - new Column('comment_false', Type::getType('integer'), ['comment' => 'false']), - ['comment'], - new Column('comment_false', Type::getType('integer'), ['comment' => false]) - ); - // Change type to custom type from empty string commented column. $tableDiff->changedColumns['comment_empty_string'] = new ColumnDiff( 'comment_empty_string', @@ -804,10 +781,10 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void new Column('comment_empty_string', Type::getType('integer'), ['comment' => '']) ); - // Change comment to false-comment from zero-string commented column. + // Change comment to empty comment from zero-string commented column. $tableDiff->changedColumns['comment_string_0'] = new ColumnDiff( 'comment_string_0', - new Column('comment_string_0', Type::getType('integer'), ['comment' => false]), + new Column('comment_string_0', Type::getType('integer'), ['comment' => '']), ['comment'], new Column('comment_string_0', Type::getType('integer'), ['comment' => '0']) ); @@ -860,20 +837,12 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void new Column('comment_with_string_literal_char', Type::getType('array'), ['comment' => "O'Reilly"]) ); - $tableDiff->removedColumns['comment_integer_0'] = new Column('comment_integer_0', Type::getType('integer'), ['comment' => 0]); - self::assertEquals( [ - // Renamed columns. - "sp_RENAME 'mytable.comment_float_0', 'comment_double_0', 'COLUMN'", - // Added columns. 'ALTER TABLE mytable ADD added_comment_none INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_null INT NOT NULL', - 'ALTER TABLE mytable ADD added_comment_false INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_empty_string INT NOT NULL', - 'ALTER TABLE mytable ADD added_comment_integer_0 INT NOT NULL', - 'ALTER TABLE mytable ADD added_comment_float_0 INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_string_0 INT NOT NULL', 'ALTER TABLE mytable ADD added_comment INT NOT NULL', 'ALTER TABLE mytable ADD [added_comment_quoted] INT NOT NULL', @@ -881,7 +850,6 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void 'ALTER TABLE mytable ADD added_commented_type VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ADD added_commented_type_with_comment VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ADD added_comment_with_string_literal_char NVARCHAR(255) NOT NULL', - 'ALTER TABLE mytable DROP COLUMN comment_integer_0', 'ALTER TABLE mytable ALTER COLUMN comment_null NVARCHAR(255) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN comment_empty_string VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN [comment_quoted] VARCHAR(MAX) NOT NULL', @@ -889,8 +857,6 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void 'ALTER TABLE mytable ALTER COLUMN commented_type INT NOT NULL', // Added columns. - "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_integer_0", - "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_float_0", "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_string_0", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment", "EXEC sp_addextendedproperty N'MS_Description', N'rulez', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [added_comment_quoted]", @@ -901,7 +867,6 @@ public function testGeneratesAlterTableSQLWithColumnComments() : void // Changed columns. "EXEC sp_addextendedproperty N'MS_Description', N'primary', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', id", - "EXEC sp_addextendedproperty N'MS_Description', N'false', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_false", "EXEC sp_addextendedproperty N'MS_Description', N'(DC2Type:object)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_empty_string", "EXEC sp_dropextendedproperty N'MS_Description', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_string_0", "EXEC sp_dropextendedproperty N'MS_Description', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment", @@ -996,30 +961,33 @@ public function testInitializesDoctrineTypeMappings() : void self::assertSame('guid', $this->platform->getDoctrineTypeMapping('uniqueidentifier')); } - protected function getBinaryMaxLength() : int + protected function getExpectedFixedLengthStringTypeDeclarationSQLNoLength() : string { - return 8000; + return 'NCHAR'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + protected function getExpectedFixedLengthStringTypeDeclarationSQLWithLength() : string { - self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('VARBINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8000])); + return 'NCHAR(16)'; + } - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8000])); + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthStringTypeDeclarationSQLNoLength(); } - /** - * @group legacy - * @expectedDeprecation Binary field length 8001 is greater than supported by the platform (8000). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void + protected function getExpectedVariableLengthStringTypeDeclarationSQLWithLength() : string { - self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8001])); - self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8001])); + return 'NVARCHAR(16)'; + } + + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthBinaryTypeDeclarationSQLNoLength(); } /** @@ -1067,23 +1035,25 @@ public function testChangeColumnsTypeWithDefaultValue() : void $tableDiff->changedColumns['col_string'] = new ColumnDiff( 'col_string', - new Column('col_string', Type::getType('string'), ['default' => 666, 'fixed' => true]), + new Column('col_string', Type::getType('string'), [ + 'length' => 255, + 'fixed' => true, + 'default' => 'foo', + ]), ['fixed'], - new Column('col_string', Type::getType('string'), ['default' => 666]) + new Column('col_string', Type::getType('string'), ['default' => 'foo']) ); - $expected = $this->platform->getAlterTableSQL($tableDiff); - self::assertSame( - $expected, [ 'ALTER TABLE column_def_change_type DROP CONSTRAINT DF_829302E0_FA2CB292', 'ALTER TABLE column_def_change_type ALTER COLUMN col_int INT NOT NULL', 'ALTER TABLE column_def_change_type ADD CONSTRAINT DF_829302E0_FA2CB292 DEFAULT 666 FOR col_int', 'ALTER TABLE column_def_change_type DROP CONSTRAINT DF_829302E0_2725A6D0', 'ALTER TABLE column_def_change_type ALTER COLUMN col_string NCHAR(255) NOT NULL', - "ALTER TABLE column_def_change_type ADD CONSTRAINT DF_829302E0_2725A6D0 DEFAULT '666' FOR col_string", - ] + "ALTER TABLE column_def_change_type ADD CONSTRAINT DF_829302E0_2725A6D0 DEFAULT 'foo' FOR col_string", + ], + $this->platform->getAlterTableSQL($tableDiff) ); } @@ -1154,6 +1124,7 @@ protected function getQuotesDropConstraintSQL() : string */ public function testGeneratesIdentifierNamesInDefaultConstraintDeclarationSQL(string $table, array $column, string $expectedSql) : void { + assert($this->platform instanceof SQLServerPlatform); self::assertSame($expectedSql, $this->platform->getDefaultConstraintDeclarationSQL($table, $column)); } @@ -1193,7 +1164,12 @@ public static function getGeneratesIdentifierNamesInCreateTableSQL() : iterable return [ // Unquoted identifiers non-reserved keywords. [ - new Table('mytable', [new Column('mycolumn', Type::getType('string'), ['default' => 'foo'])]), + new Table('mytable', [ + new Column('mycolumn', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ]), [ 'CREATE TABLE mytable (mycolumn NVARCHAR(255) NOT NULL)', "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR mycolumn", @@ -1201,7 +1177,12 @@ public static function getGeneratesIdentifierNamesInCreateTableSQL() : iterable ], // Quoted identifiers reserved keywords. [ - new Table('`mytable`', [new Column('`mycolumn`', Type::getType('string'), ['default' => 'foo'])]), + new Table('`mytable`', [ + new Column('`mycolumn`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ]), [ 'CREATE TABLE [mytable] ([mycolumn] NVARCHAR(255) NOT NULL)', "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR [mycolumn]", @@ -1209,7 +1190,12 @@ public static function getGeneratesIdentifierNamesInCreateTableSQL() : iterable ], // Unquoted identifiers reserved keywords. [ - new Table('table', [new Column('select', Type::getType('string'), ['default' => 'foo'])]), + new Table('table', [ + new Column('select', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ]), [ 'CREATE TABLE [table] ([select] NVARCHAR(255) NOT NULL)', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]", @@ -1217,7 +1203,12 @@ public static function getGeneratesIdentifierNamesInCreateTableSQL() : iterable ], // Quoted identifiers reserved keywords. [ - new Table('`table`', [new Column('`select`', Type::getType('string'), ['default' => 'foo'])]), + new Table('`table`', [ + new Column('`select`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ]), [ 'CREATE TABLE [table] ([select] NVARCHAR(255) NOT NULL)', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]", @@ -1247,16 +1238,32 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL() : iterable [ new TableDiff( 'mytable', - [new Column('addcolumn', Type::getType('string'), ['default' => 'foo'])], + [ + 'addcolumn' => new Column('addcolumn', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ], [ 'mycolumn' => new ColumnDiff( 'mycolumn', - new Column('mycolumn', Type::getType('string'), ['default' => 'bar']), + new Column('mycolumn', Type::getType('string'), [ + 'length' => 255, + 'default' => 'bar', + ]), ['default'], - new Column('mycolumn', Type::getType('string'), ['default' => 'foo']) + new Column('mycolumn', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]) ), ], - [new Column('removecolumn', Type::getType('string'), ['default' => 'foo'])] + [ + 'removecolumn' => new Column('removecolumn', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ] ), [ 'ALTER TABLE mytable ADD addcolumn NVARCHAR(255) NOT NULL', @@ -1271,16 +1278,32 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL() : iterable [ new TableDiff( '`mytable`', - [new Column('`addcolumn`', Type::getType('string'), ['default' => 'foo'])], + [ + 'addcolumn' => new Column('`addcolumn`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ], [ 'mycolumn' => new ColumnDiff( '`mycolumn`', - new Column('`mycolumn`', Type::getType('string'), ['default' => 'bar']), + new Column('`mycolumn`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'bar', + ]), ['default'], - new Column('`mycolumn`', Type::getType('string'), ['default' => 'foo']) + new Column('`mycolumn`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]) ), ], - [new Column('`removecolumn`', Type::getType('string'), ['default' => 'foo'])] + [ + 'removecolumn' => new Column('`removecolumn`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ] ), [ 'ALTER TABLE [mytable] ADD [addcolumn] NVARCHAR(255) NOT NULL', @@ -1295,16 +1318,32 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL() : iterable [ new TableDiff( 'table', - [new Column('add', Type::getType('string'), ['default' => 'foo'])], + [ + 'add' => new Column('add', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ], [ 'select' => new ColumnDiff( 'select', - new Column('select', Type::getType('string'), ['default' => 'bar']), + new Column('select', Type::getType('string'), [ + 'length' => 255, + 'default' => 'bar', + ]), ['default'], - new Column('select', Type::getType('string'), ['default' => 'foo']) + new Column('select', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]) ), ], - [new Column('drop', Type::getType('string'), ['default' => 'foo'])] + [ + 'drop' => new Column('drop', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ] ), [ 'ALTER TABLE [table] ADD [add] NVARCHAR(255) NOT NULL', @@ -1319,16 +1358,32 @@ public static function getGeneratesIdentifierNamesInAlterTableSQL() : iterable [ new TableDiff( '`table`', - [new Column('`add`', Type::getType('string'), ['default' => 'foo'])], + [ + 'add' => new Column('`add`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ], [ 'select' => new ColumnDiff( '`select`', - new Column('`select`', Type::getType('string'), ['default' => 'bar']), + new Column('`select`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'bar', + ]), ['default'], - new Column('`select`', Type::getType('string'), ['default' => 'foo']) + new Column('`select`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]) ), ], - [new Column('`drop`', Type::getType('string'), ['default' => 'foo'])] + [ + 'drop' => new Column('`drop`', Type::getType('string'), [ + 'length' => 255, + 'default' => 'foo', + ]), + ] ), [ 'ALTER TABLE [table] ADD [add] NVARCHAR(255) NOT NULL', @@ -1416,7 +1471,7 @@ public static function getReturnsForeignKeyReferentialActionSQL() : iterable */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { - return 'CONSTRAINT [select] UNIQUE (foo) WHERE foo IS NOT NULL'; + return 'CONSTRAINT [select] UNIQUE (foo)'; } /** @@ -1565,8 +1620,8 @@ public function testColumnCollationDeclarationSQL() : void public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); - $table->addColumn('no_collation', 'string'); - $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'Latin1_General_CS_AS_KS_WS'); + $table->addColumn('no_collation', 'string', ['length' => 255]); + $table->addColumn('column_collation', 'string', ['length' => 255])->setPlatformOption('collation', 'Latin1_General_CS_AS_KS_WS'); self::assertSame( ['CREATE TABLE foo (no_collation NVARCHAR(255) NOT NULL, column_collation NVARCHAR(255) COLLATE Latin1_General_CS_AS_KS_WS NOT NULL)'], diff --git a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php index a0c1f1f4b4b..1a6d39448d7 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php @@ -1,7 +1,10 @@ true, ]; - self::assertEquals('VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([])); - self::assertEquals('VARCHAR(10)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 10])); - self::assertEquals('CHAR(254)', $this->platform->getVarcharTypeDeclarationSQL(['fixed' => true])); - self::assertEquals('CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL($fullColumnDef)); - self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([])); self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('SMALLINT GENERATED BY DEFAULT AS IDENTITY', $this->platform->getSmallIntTypeDeclarationSQL($fullColumnDef)); @@ -306,13 +304,17 @@ public function testInitializesDoctrineTypeMappings() : void /** * {@inheritDoc} */ - public function getIsCommentedDoctrineType() : array + public function getIsCommentedDoctrineType() : iterable { - $data = parent::getIsCommentedDoctrineType(); + $types = []; + + foreach (parent::getIsCommentedDoctrineType() as $key => $value) { + $types[$key] = $value; + } - $data[Types::BOOLEAN] = [Type::getType(Types::BOOLEAN), true]; + $types[Types::BOOLEAN] = [Type::getType(Types::BOOLEAN), true]; - return $data; + return $types; } public function testGeneratesDDLSnippets() : void @@ -321,7 +323,6 @@ public function testGeneratesDDLSnippets() : void self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals('DECLARE GLOBAL TEMPORARY TABLE', $this->platform->getCreateTemporaryTableSnippetSQL()); self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar')); - self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); @@ -344,36 +345,35 @@ public function testGeneratesSQLSnippets() : void self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); - self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); - self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); - self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' + 15 MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' + 21 DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); + self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", '4')); + self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", '12')); + self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", '102')); + self::assertEquals("'1987/05/02' + (5 * 3) MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("'1987/05/02' + (3 * 7) DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", '10')); self::assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); - self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); - self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); - self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); - self::assertEquals("'1987/05/02' - 15 MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("'1987/05/02' - 21 DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); + self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", '4')); + self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", '12')); + self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", '102')); + self::assertEquals("'1987/05/02' - (5 * 3) MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("'1987/05/02' - (3 * 7) DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", '10')); self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); - self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5)); - self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); + self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', '1')); + self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', '5')); + self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', '5', '2')); } public function testModifiesLimitQuery() : void { self::assertEquals( 'SELECT * FROM user', - $this->platform->modifyLimitQuery('SELECT * FROM user', null, null) + $this->platform->modifyLimitQuery('SELECT * FROM user', null, 0) ); self::assertEquals( @@ -426,34 +426,38 @@ public function testReturnsSQLResultCasing() : void self::assertSame('COL', $this->platform->getSQLResultCasing('cOl')); } - protected function getBinaryDefaultLength() : int + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthStringTypeDeclarationSQLNoLength(); + } + + public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string { - return 1; + return 'CHAR FOR BIT DATA'; } - protected function getBinaryMaxLength() : int + public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string { - return 32704; + return 'CHAR(16) FOR BIT DATA'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string { - self::assertSame('VARCHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('VARCHAR(255) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('VARCHAR(32704) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32704])); + return 'CHAR(16) FOR BIT DATA'; + } - self::assertSame('CHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('CHAR(254) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthBinaryTypeDeclarationSQLNoLength(); } - /** - * @group legacy - * @expectedDeprecation Binary field length 32705 is greater than supported by the platform (32704). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void + public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string { - self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32705])); - self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32705])); + return 'VARCHAR(16) FOR BIT DATA'; } /** diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php index 00b86088ad5..cf8493886b5 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php @@ -1,5 +1,7 @@ createPlatform(); - $platform->assertValidIdentifier($identifier); + OraclePlatform::assertValidIdentifier($identifier); $this->addToAssertionCount(1); } @@ -72,8 +75,7 @@ public function testInvalidIdentifiers(string $identifier) : void { $this->expectException(DBALException::class); - $platform = $this->createPlatform(); - $platform->assertValidIdentifier($identifier); + OraclePlatform::assertValidIdentifier($identifier); } public function createPlatform() : AbstractPlatform @@ -178,26 +180,6 @@ public function testGeneratesTypeDeclarationForIntegers() : void ); } - public function testGeneratesTypeDeclarationsForStrings() : void - { - self::assertEquals( - 'CHAR(10)', - $this->platform->getVarcharTypeDeclarationSQL( - ['length' => 10, 'fixed' => true] - ) - ); - self::assertEquals( - 'VARCHAR2(50)', - $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), - 'Variable string declaration is not correct' - ); - self::assertEquals( - 'VARCHAR2(255)', - $this->platform->getVarcharTypeDeclarationSQL([]), - 'Long string declaration is not correct' - ); - } - public function testPrefersIdentityColumns() : void { self::assertFalse($this->platform->prefersIdentityColumns()); @@ -244,7 +226,7 @@ public function getGenerateForeignKeySql() : string */ public function testGeneratesAdvancedForeignKeyOptionsSQL(array $options, string $expectedSql) : void { - $foreignKey = new ForeignKeyConstraint(['foo'], 'foreign_table', ['bar'], null, $options); + $foreignKey = new ForeignKeyConstraint(['foo'], 'foreign_table', ['bar'], '', $options); self::assertSame($expectedSql, $this->platform->getAdvancedForeignKeyOptionsSQL($foreignKey)); } @@ -319,7 +301,8 @@ public function testGenerateTableWithAutoincrement() : void $columnName = strtoupper('id' . uniqid()); $tableName = strtoupper('table' . uniqid()); $table = new Table($tableName); - $column = $table->addColumn($columnName, 'integer'); + + $column = $table->addColumn($columnName, 'integer'); $column->setAutoincrement(true); $targets = [ sprintf('CREATE TABLE %s (%s NUMBER(10) NOT NULL)', $tableName, $columnName), @@ -453,31 +436,45 @@ protected function getQuotedColumnInForeignKeySQL() : array */ public function testAlterTableNotNULL() : void { - $tableDiff = new TableDiff('mytable'); - $tableDiff->changedColumns['foo'] = new ColumnDiff( + $tableDiff = new TableDiff('mytable'); + + $tableDiff->changedColumns['foo'] = new ColumnDiff( 'foo', new Column( 'foo', Type::getType('string'), - ['default' => 'bla', 'notnull' => true] + [ + 'length' => 255, + 'default' => 'bla', + 'notnull' => true, + ] ), ['type'] ); - $tableDiff->changedColumns['bar'] = new ColumnDiff( + + $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column( 'baz', Type::getType('string'), - ['default' => 'bla', 'notnull' => true] + [ + 'length' => 255, + 'default' => 'bla', + 'notnull' => true, + ] ), ['type', 'notnull'] ); + $tableDiff->changedColumns['metar'] = new ColumnDiff( 'metar', new Column( 'metar', Type::getType('string'), - ['length' => 2000, 'notnull' => false] + [ + 'length' => 2000, + 'notnull' => false, + ] ), ['notnull'] ); @@ -501,30 +498,40 @@ public function testInitializesDoctrineTypeMappings() : void self::assertSame('date', $this->platform->getDoctrineTypeMapping('date')); } - protected function getBinaryMaxLength() : int + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthStringTypeDeclarationSQLNoLength(); + } + + protected function getExpectedVariableLengthStringTypeDeclarationSQLWithLength() : string { - return 2000; + return 'VARCHAR2(16)'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function testGetFixedLengthBinaryTypeDeclarationSQLNoLength() : void { - self::assertSame('RAW(255)', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2000])); + $this->expectException(ColumnLengthRequired::class); - self::assertSame('RAW(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2000])); + parent::testGetFixedLengthBinaryTypeDeclarationSQLNoLength(); } - /** - * @group legacy - * @expectedDeprecation Binary field length 2001 is greater than supported by the platform (2000). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void + public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string { - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2001])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2001])); + return 'RAW(16)'; + } + + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void + { + $this->expectException(ColumnLengthRequired::class); + + parent::testGetVariableLengthBinaryTypeDeclarationSQLNoLength(); + } + + public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string + { + return 'RAW(16)'; } public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void @@ -539,9 +546,13 @@ public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : v $comparator = new Comparator(); + $diff = $comparator->diffTable($table1, $table2); + + self::assertNotNull($diff); + // VARBINARY -> BINARY // BINARY -> VARBINARY - self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); + self::assertEmpty($this->platform->getAlterTableSQL($diff)); } /** @@ -687,6 +698,8 @@ public function getAlterTableRenameColumnSQL() : array */ public function testReturnsDropAutoincrementSQL(string $table, array $expectedSql) : void { + assert($this->platform instanceof OraclePlatform); + self::assertSame($expectedSql, $this->platform->getDropAutoincrementSql($table)); } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php deleted file mode 100644 index 3ed82529e08..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php +++ /dev/null @@ -1,41 +0,0 @@ -platform->supportsColumnCollation()); - } - - public function testColumnCollationDeclarationSQL() : void - { - self::assertSame( - 'COLLATE "en_US.UTF-8"', - $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') - ); - } - - public function testGetCreateTableSQLWithColumnCollation() : void - { - $table = new Table('foo'); - $table->addColumn('no_collation', 'string'); - $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'en_US.UTF-8'); - - self::assertSame( - ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE "en_US.UTF-8")'], - $this->platform->getCreateTableSQL($table), - 'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column' - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php deleted file mode 100644 index 7fbedd494be..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php +++ /dev/null @@ -1,72 +0,0 @@ -platform->hasNativeJsonType()); - } - - /** - * @group DBAL-553 - */ - public function testReturnsJsonTypeDeclarationSQL() : void - { - self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); - } - - public function testReturnsSmallIntTypeDeclarationSQL() : void - { - self::assertSame( - 'SMALLSERIAL', - $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) - ); - - self::assertSame( - 'SMALLINT', - $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => false]) - ); - - self::assertSame( - 'SMALLINT', - $this->platform->getSmallIntTypeDeclarationSQL([]) - ); - } - - /** - * @group DBAL-553 - */ - public function testInitializesJsonTypeMapping() : void - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); - self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); - } - - /** - * @group DBAL-1220 - */ - public function testReturnsCloseActiveDatabaseConnectionsSQL() : void - { - self::assertSame( - "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", - $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php index 179e005b2f9..4d18f199fc5 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php @@ -1,12 +1,14 @@ platform->supportsPartialIndexes()); } + + public function testColumnCollationDeclarationSQL() : void + { + self::assertEquals( + 'COLLATE "en_US.UTF-8"', + $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') + ); + } + + /** + * @group DBAL-553 + */ + public function testHasNativeJsonType() : void + { + self::assertTrue($this->platform->hasNativeJsonType()); + } + + /** + * @group DBAL-553 + */ + public function testReturnsJsonTypeDeclarationSQL() : void + { + self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); + } + + public function testReturnsSmallIntTypeDeclarationSQL() : void + { + self::assertSame( + 'SMALLSERIAL', + $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) + ); + + self::assertSame( + 'SMALLINT', + $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => false]) + ); + + self::assertSame( + 'SMALLINT', + $this->platform->getSmallIntTypeDeclarationSQL([]) + ); + } + + /** + * @group DBAL-553 + */ + public function testInitializesJsonTypeMapping() : void + { + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); + self::assertEquals(Type::JSON, $this->platform->getDoctrineTypeMapping('json')); + } + + /** + * @group DBAL-1220 + */ + public function testReturnsCloseActiveDatabaseConnectionsSQL() : void + { + assert($this->platform instanceof PostgreSqlPlatform); + + self::assertSame( + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", + $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') + ); + } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php b/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php index 8d07f62274d..186cfdaeebc 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php @@ -1,5 +1,7 @@ markTestSkipped('This version of the platform now supports regular expressions.'); - } - - public function testGeneratesRegularExpressionSQLSnippet() : void - { - self::assertEquals('REGEXP', $this->platform->getRegexpExpression()); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php deleted file mode 100644 index e60f6b1c7f1..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php +++ /dev/null @@ -1,142 +0,0 @@ -markTestSkipped('This version of the platform now supports sequences.'); - } - - public function testSupportsSequences() : void - { - self::assertTrue($this->platform->supportsSequences()); - } - - public function testGeneratesSequenceSqlCommands() : void - { - $sequence = new Sequence('myseq', 20, 1); - self::assertEquals( - 'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1', - $this->platform->getCreateSequenceSQL($sequence) - ); - self::assertEquals( - 'ALTER SEQUENCE myseq INCREMENT BY 20', - $this->platform->getAlterSequenceSQL($sequence) - ); - self::assertEquals( - 'DROP SEQUENCE myseq', - $this->platform->getDropSequenceSQL('myseq') - ); - self::assertEquals( - 'DROP SEQUENCE myseq', - $this->platform->getDropSequenceSQL($sequence) - ); - self::assertEquals( - 'SELECT myseq.NEXTVAL', - $this->platform->getSequenceNextValSQL('myseq') - ); - self::assertEquals( - 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE', - $this->platform->getListSequencesSQL(null) - ); - } - - public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() : void - { - self::assertEquals( - 'TIMESTAMP WITH TIME ZONE', - $this->platform->getDateTimeTzTypeDeclarationSQL([ - 'length' => 10, - 'fixed' => true, - 'unsigned' => true, - 'autoincrement' => true, - ]) - ); - } - - public function testHasCorrectDateTimeTzFormatString() : void - { - self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); - } - - public function testInitializesDateTimeTzTypeMapping() : void - { - self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); - self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); - } - - public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void - { - self::assertEquals( - 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - true, - false, - ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] - ), - 'footable' - ) - ); - self::assertEquals( - 'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] - ), - 'footable' - ) - ); - - // WITH NULLS NOT DISTINCT clause not available on primary indexes. - self::assertEquals( - 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - true, - ['with_nulls_not_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS NOT DISTINCT clause not available on non-unique indexes. - self::assertEquals( - 'CREATE INDEX fooindex ON footable (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_not_distinct'] - ), - 'footable' - ) - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php deleted file mode 100644 index a6a0018a06e..00000000000 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php +++ /dev/null @@ -1,80 +0,0 @@ -platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - true, - false, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS DISTINCT clause not available on primary indexes. - self::assertEquals( - 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - true, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - // WITH NULLS DISTINCT clause not available on non-unique indexes. - self::assertEquals( - 'CREATE INDEX fooindex ON footable (a, b)', - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_distinct'] - ), - 'footable' - ) - ); - - parent::testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL(); - } - - public function testThrowsExceptionOnInvalidWithNullsNotDistinctIndexOptions() : void - { - $this->expectException('UnexpectedValueException'); - - $this->platform->getCreateIndexSQL( - new Index( - 'fooindex', - ['a', 'b'], - false, - false, - ['with_nulls_distinct', 'with_nulls_not_distinct'] - ), - 'footable' - ); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php index 0efa23b19c6..b82dc833a18 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php @@ -1,8 +1,11 @@ platform->getDateTimeTypeDeclarationSQL($fullColumnDef)); self::assertEquals('TIME', $this->platform->getTimeTypeDeclarationSQL($fullColumnDef)); self::assertEquals('UNIQUEIDENTIFIER', $this->platform->getGuidTypeDeclarationSQL($fullColumnDef)); - - self::assertEquals(1, $this->platform->getVarcharDefaultLength()); - self::assertEquals(32767, $this->platform->getVarcharMaxLength()); } public function testHasNativeGuidType() : void @@ -336,7 +334,6 @@ public function testGeneratesDDLSnippets() : void self::assertEquals('STOP DATABASE "foobar" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('"foobar"')); self::assertEquals('STOP DATABASE "create" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('create')); self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar')); - self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); @@ -391,12 +388,12 @@ public function testGeneratesUniqueConstraintDeclarationSQL() : void 'CONSTRAINT unique_constraint UNIQUE CLUSTERED (a, b)', $this->platform->getUniqueConstraintDeclarationSQL( 'unique_constraint', - new Index(null, ['a', 'b'], true, false, ['clustered']) + new UniqueConstraint('', ['a', 'b'], ['clustered']) ) ); self::assertEquals( - 'UNIQUE (a, b)', - $this->platform->getUniqueConstraintDeclarationSQL(null, new Index(null, ['a', 'b'], true, false)) + 'CONSTRAINT UNIQUE (a, b)', + $this->platform->getUniqueConstraintDeclarationSQL('', new UniqueConstraint('', ['a', 'b'])) ); } @@ -404,7 +401,7 @@ public function testCannotGenerateUniqueConstraintDeclarationSQLWithEmptyColumns { $this->expectException(InvalidArgumentException::class); - $this->platform->getUniqueConstraintDeclarationSQL('constr', new Index('constr', [], true)); + $this->platform->getUniqueConstraintDeclarationSQL('constr', new UniqueConstraint('constr', [])); } public function testGeneratesForeignKeyConstraintsWithAdvancedPlatformOptionsSQL() : void @@ -484,20 +481,123 @@ public function testCannotGenerateCustomConstraintWithCreateConstraintSQL() : vo public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void { self::assertEquals( - 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', + 'CREATE UNIQUE INDEX fooindex ON footable (a, b) WITH NULLS DISTINCT', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + true, + false, + ['with_nulls_distinct'] + ), + 'footable' + ) + ); + + // WITH NULLS DISTINCT clause not available on primary indexes. + self::assertEquals( + 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + true, + ['with_nulls_distinct'] + ), + 'footable' + ) + ); + + // WITH NULLS DISTINCT clause not available on non-unique indexes. + self::assertEquals( + 'CREATE INDEX fooindex ON footable (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_distinct'] + ), + 'footable' + ) + ); + + self::assertEquals( + 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + true, + false, + ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] + ), + 'footable' + ) + ); + self::assertEquals( + 'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] + ), + 'footable' + ) + ); + + // WITH NULLS NOT DISTINCT clause not available on primary indexes. + self::assertEquals( + 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], + false, true, + ['with_nulls_not_distinct'] + ), + 'footable' + ) + ); + + // WITH NULLS NOT DISTINCT clause not available on non-unique indexes. + self::assertEquals( + 'CREATE INDEX fooindex ON footable (a, b)', + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, false, - ['virtual', 'clustered', 'for_olap_workload'] + ['with_nulls_not_distinct'] ), 'footable' ) ); } + public function testThrowsExceptionOnInvalidWithNullsNotDistinctIndexOptions() : void + { + $this->expectException('UnexpectedValueException'); + + $this->platform->getCreateIndexSQL( + new Index( + 'fooindex', + ['a', 'b'], + false, + false, + ['with_nulls_distinct', 'with_nulls_not_distinct'] + ), + 'footable' + ); + } + public function testDoesNotSupportIndexDeclarationInCreateAlterTableStatements() : void { $this->expectException(DBALException::class); @@ -542,32 +642,31 @@ public function testGeneratesSQLSnippets() : void self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); - self::assertEquals("DATEADD(DAY, 4, '1987/05/02')", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); - self::assertEquals("DATEADD(HOUR, 12, '1987/05/02')", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); - self::assertEquals("DATEADD(MINUTE, 2, '1987/05/02')", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("DATEADD(MONTH, 102, '1987/05/02')", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); - self::assertEquals("DATEADD(QUARTER, 5, '1987/05/02')", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("DATEADD(SECOND, 1, '1987/05/02')", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("DATEADD(WEEK, 3, '1987/05/02')", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("DATEADD(YEAR, 10, '1987/05/02')", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); + self::assertEquals("DATEADD(DAY, 4, '1987/05/02')", $this->platform->getDateAddDaysExpression("'1987/05/02'", '4')); + self::assertEquals("DATEADD(HOUR, 12, '1987/05/02')", $this->platform->getDateAddHourExpression("'1987/05/02'", '12')); + self::assertEquals("DATEADD(MINUTE, 2, '1987/05/02')", $this->platform->getDateAddMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("DATEADD(MONTH, 102, '1987/05/02')", $this->platform->getDateAddMonthExpression("'1987/05/02'", '102')); + self::assertEquals("DATEADD(QUARTER, 5, '1987/05/02')", $this->platform->getDateAddQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("DATEADD(SECOND, 1, '1987/05/02')", $this->platform->getDateAddSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("DATEADD(WEEK, 3, '1987/05/02')", $this->platform->getDateAddWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("DATEADD(YEAR, 10, '1987/05/02')", $this->platform->getDateAddYearsExpression("'1987/05/02'", '10')); self::assertEquals("DATEDIFF(day, '1987/04/01', '1987/05/02')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); - self::assertEquals("DATEADD(DAY, -1 * 4, '1987/05/02')", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); - self::assertEquals("DATEADD(HOUR, -1 * 12, '1987/05/02')", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); - self::assertEquals("DATEADD(MINUTE, -1 * 2, '1987/05/02')", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); - self::assertEquals("DATEADD(MONTH, -1 * 102, '1987/05/02')", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); - self::assertEquals("DATEADD(QUARTER, -1 * 5, '1987/05/02')", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); - self::assertEquals("DATEADD(SECOND, -1 * 1, '1987/05/02')", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); - self::assertEquals("DATEADD(WEEK, -1 * 3, '1987/05/02')", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); - self::assertEquals("DATEADD(YEAR, -1 * 10, '1987/05/02')", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); + self::assertEquals("DATEADD(DAY, -1 * 4, '1987/05/02')", $this->platform->getDateSubDaysExpression("'1987/05/02'", '4')); + self::assertEquals("DATEADD(HOUR, -1 * 12, '1987/05/02')", $this->platform->getDateSubHourExpression("'1987/05/02'", '12')); + self::assertEquals("DATEADD(MINUTE, -1 * 2, '1987/05/02')", $this->platform->getDateSubMinutesExpression("'1987/05/02'", '2')); + self::assertEquals("DATEADD(MONTH, -1 * 102, '1987/05/02')", $this->platform->getDateSubMonthExpression("'1987/05/02'", '102')); + self::assertEquals("DATEADD(QUARTER, -1 * 5, '1987/05/02')", $this->platform->getDateSubQuartersExpression("'1987/05/02'", '5')); + self::assertEquals("DATEADD(SECOND, -1 * 1, '1987/05/02')", $this->platform->getDateSubSecondsExpression("'1987/05/02'", '1')); + self::assertEquals("DATEADD(WEEK, -1 * 3, '1987/05/02')", $this->platform->getDateSubWeeksExpression("'1987/05/02'", '3')); + self::assertEquals("DATEADD(YEAR, -1 * 10, '1987/05/02')", $this->platform->getDateSubYearsExpression("'1987/05/02'", '10')); self::assertEquals('Y-m-d H:i:s.u', $this->platform->getDateTimeFormatString()); self::assertEquals('H:i:s.u', $this->platform->getTimeFormatString()); self::assertEquals('', $this->platform->getForUpdateSQL()); - self::assertEquals('NEWID()', $this->platform->getGuidExpression()); self::assertEquals('LOCATE(string_column, substring_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); - self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); + self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', '1')); self::assertEquals("HASH(column, 'MD5')", $this->platform->getMd5Expression('column')); - self::assertEquals('SUBSTRING(column, 5)', $this->platform->getSubstringExpression('column', 5)); - self::assertEquals('SUBSTRING(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); + self::assertEquals('SUBSTRING(column, 5)', $this->platform->getSubstringExpression('column', '5')); + self::assertEquals('SUBSTRING(column, 5, 2)', $this->platform->getSubstringExpression('column', '5', '2')); self::assertEquals('GLOBAL TEMPORARY', $this->platform->getTemporaryTableSQL()); self::assertEquals( 'LTRIM(column)', @@ -593,11 +692,6 @@ public function testGeneratesSQLSnippets() : void "REVERSE(SUBSTR(REVERSE(column), PATINDEX('%[^' + c + ']%', REVERSE(column))))", $this->platform->getTrimExpression('column', TrimMode::TRAILING, 'c') ); - self::assertEquals( - "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . - "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", - $this->platform->getTrimExpression('column', null, 'c') - ); self::assertEquals( "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", @@ -605,19 +699,28 @@ public function testGeneratesSQLSnippets() : void ); } - public function testDoesNotSupportRegexp() : void + public function testHasCorrectDateTimeTzFormatString() : void { - $this->expectException(DBALException::class); + self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); + } - $this->platform->getRegexpExpression(); + public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() : void + { + self::assertEquals( + 'TIMESTAMP WITH TIME ZONE', + $this->platform->getDateTimeTzTypeDeclarationSQL([ + 'length' => 10, + 'fixed' => true, + 'unsigned' => true, + 'autoincrement' => true, + ]) + ); } - public function testHasCorrectDateTimeTzFormatString() : void + public function testInitializesDateTimeTzTypeMapping() : void { - // Date time type with timezone is not supported before version 12. - // For versions before we have to ensure that the date time with timezone format - // equals the normal date time format so that it corresponds to the declaration SQL equality (datetimetz -> datetime). - self::assertEquals($this->platform->getDateTimeFormatString(), $this->platform->getDateTimeTzFormatString()); + self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); + self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); } public function testHasCorrectDefaultTransactionIsolationLevel() : void @@ -648,13 +751,6 @@ public function testGeneratesTransactionsCommands() : void ); } - public function testCannotGenerateTransactionCommandWithInvalidIsolationLevel() : void - { - $this->expectException(InvalidArgumentException::class); - - $this->platform->getSetTransactionIsolationSQL('invalid_transaction_isolation_level'); - } - public function testModifiesLimitQuery() : void { self::assertEquals( @@ -776,7 +872,37 @@ public function testSupportsGettingAffectedRows() : void public function testDoesNotSupportSequences() : void { - self::assertFalse($this->platform->supportsSequences()); + self::markTestSkipped('This version of the platform now supports sequences.'); + } + + public function testSupportsSequences() : void + { + self::assertTrue($this->platform->supportsSequences()); + } + + public function testGeneratesSequenceSqlCommands() : void + { + $sequence = new Sequence('myseq', 20, 1); + self::assertEquals( + 'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1', + $this->platform->getCreateSequenceSQL($sequence) + ); + self::assertEquals( + 'ALTER SEQUENCE myseq INCREMENT BY 20', + $this->platform->getAlterSequenceSQL($sequence) + ); + self::assertEquals( + 'DROP SEQUENCE myseq', + $this->platform->getDropSequenceSQL('myseq') + ); + self::assertEquals( + 'DROP SEQUENCE myseq', + $this->platform->getDropSequenceSQL($sequence) + ); + self::assertEquals( + 'SELECT myseq.NEXTVAL', + $this->platform->getSequenceNextValSQL('myseq') + ); } public function testDoesNotSupportInlineColumnComments() : void @@ -801,35 +927,18 @@ public function testInitializesDoctrineTypeMappings() : void self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary')); } - protected function getBinaryDefaultLength() : int + public function testGetVariableLengthStringTypeDeclarationSQLNoLength() : void { - return 1; - } + $this->expectException(ColumnLengthRequired::class); - protected function getBinaryMaxLength() : int - { - return 32767; + parent::testGetVariableLengthStringTypeDeclarationSQLNoLength(); } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function testGetVariableLengthBinaryTypeDeclarationSQLNoLength() : void { - self::assertSame('VARBINARY(1)', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('VARBINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('VARBINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32767])); - - self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32767])); - } + $this->expectException(ColumnLengthRequired::class); - /** - * @group legacy - * @expectedDeprecation Binary field length 32768 is greater than supported by the platform (32767). Reduce the field length or use a BLOB field instead. - */ - public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void - { - self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32768])); - self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32768])); + parent::testGetVariableLengthBinaryTypeDeclarationSQLNoLength(); } /** @@ -1046,7 +1155,7 @@ public function testQuotesSchemaNameInListTableColumnsSQL() : void */ public function testQuotesTableNameInListTableConstraintsSQL() : void { - self::assertStringContainsStringIgnoringCase("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), '', true); + self::assertStringContainsStringIgnoringCase("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), ''); } /** diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php index 65b5e85f219..69eac4a127d 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php @@ -1,5 +1,7 @@ platform->getDateTimeTzTypeDeclarationSQL([])); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php index 18a8a0ef1d2..a85e6ac5457 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php @@ -1,5 +1,7 @@ platform->modifyLimitQuery($query, $limit, $offset)); } @@ -43,8 +43,6 @@ public static function getLockHints() : iterable { return [ [null, ''], - [false, ''], - [true, ''], [LockMode::NONE, ' WITH (NOLOCK)'], [LockMode::OPTIMISTIC, ''], [LockMode::PESSIMISTIC_READ, ' WITH (HOLDLOCK, ROWLOCK)'], @@ -62,7 +60,7 @@ public static function getModifyLimitQueries() : iterable [ 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_ ORDER BY c0_.title ASC) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, - null, + 0, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', ], @@ -70,9 +68,14 @@ public static function getModifyLimitQueries() : iterable [ 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, - null, + 0, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', ], ]; } + + public function testGeneratesTypeDeclarationForDateTimeTz() : void + { + self::assertEquals('DATETIMEOFFSET(6)', $this->platform->getDateTimeTzTypeDeclarationSQL([])); + } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index d645b218cb8..f2ab5a452ac 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -1,5 +1,7 @@ platform->getRegexpExpression(), 'Regular expression operator is not correct'); - self::assertEquals('SUBSTR(column, 5, LENGTH(column))', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); - self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); + self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', '5'), 'Substring expression without length is not correct'); + self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', '0', '5'), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() : void @@ -80,6 +83,8 @@ public function testIgnoresUnsignedIntegerDeclarationForAutoIncrementalIntegers( */ public function testGeneratesTypeDeclarationForTinyIntegers() : void { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'TINYINT', $this->platform->getTinyIntTypeDeclarationSQL([]) @@ -110,6 +115,8 @@ public function testGeneratesTypeDeclarationForTinyIntegers() : void */ public function testGeneratesTypeDeclarationForSmallIntegers() : void { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([]) @@ -144,6 +151,8 @@ public function testGeneratesTypeDeclarationForSmallIntegers() : void */ public function testGeneratesTypeDeclarationForMediumIntegers() : void { + assert($this->platform instanceof SqlitePlatform); + self::assertEquals( 'MEDIUMINT', $this->platform->getMediumIntTypeDeclarationSQL([]) @@ -236,26 +245,6 @@ public function testGeneratesTypeDeclarationForBigIntegers() : void ); } - public function testGeneratesTypeDeclarationForStrings() : void - { - self::assertEquals( - 'CHAR(10)', - $this->platform->getVarcharTypeDeclarationSQL( - ['length' => 10, 'fixed' => true] - ) - ); - self::assertEquals( - 'VARCHAR(50)', - $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), - 'Variable string declaration is not correct' - ); - self::assertEquals( - 'VARCHAR(255)', - $this->platform->getVarcharTypeDeclarationSQL([]), - 'Long string declaration is not correct' - ); - } - public function getGenerateIndexSql() : string { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; @@ -491,25 +480,24 @@ protected function getQuotedColumnInForeignKeySQL() : array ]; } - protected function getBinaryDefaultLength() : int + public function getExpectedFixedLengthBinaryTypeDeclarationSQLNoLength() : string { - return 0; + return 'BLOB'; } - protected function getBinaryMaxLength() : int + public function getExpectedFixedLengthBinaryTypeDeclarationSQLWithLength() : string { - return 0; + return 'BLOB'; } - public function testReturnsBinaryTypeDeclarationSQL() : void + public function getExpectedVariableLengthBinaryTypeDeclarationSQLNoLength() : string { - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL([])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999])); + return 'BLOB'; + } - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); - self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999])); + public function getExpectedVariableLengthBinaryTypeDeclarationSQLWithLength() : string + { + return 'BLOB'; } /** @@ -686,7 +674,7 @@ protected static function getInlineColumnCommentRequiringEscapingSQL() : string protected static function getInlineColumnEmptyCommentSQL() : string { - return "--\n"; + return ''; } /** @@ -791,12 +779,12 @@ public function testQuotesTableNameInListTableForeignKeysSQL() : void public function testDateAddStaticNumberOfDays() : void { - self::assertSame("DATE(rentalBeginsOn,'+12 DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12)); + self::assertSame("DATETIME(rentalBeginsOn,'+' || 12 || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', '12')); } public function testDateAddNumberOfDaysFromColumn() : void { - self::assertSame("DATE(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration')); + self::assertSame("DATETIME(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration')); } public function testSupportsColumnCollation() : void @@ -815,8 +803,8 @@ public function testColumnCollationDeclarationSQL() : void public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); - $table->addColumn('no_collation', 'string'); - $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'NOCASE'); + $table->addColumn('no_collation', 'string', ['length' => 255]); + $table->addColumn('column_collation', 'string', ['length' => 255])->setPlatformOption('collation', 'NOCASE'); self::assertSame( ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE NOCASE)'], diff --git a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php index c8e40214eb0..7753cda4325 100644 --- a/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php +++ b/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php @@ -1,5 +1,7 @@ wrappedStmt->expects($this->once()) ->method('bindParam') - ->with($column, $variable, $type, $length) - ->will($this->returnValue(true)); + ->with($column, $variable, $type, $length); - self::assertTrue($this->stmt->bindParam($column, $variable, $type, $length)); + $this->stmt->bindParam($column, $variable, $type, $length); } public function testBindValue() : void @@ -59,19 +60,17 @@ public function testBindValue() : void $this->wrappedStmt->expects($this->once()) ->method('bindValue') - ->with($param, $value, $type) - ->will($this->returnValue(true)); + ->with($param, $value, $type); - self::assertTrue($this->stmt->bindValue($param, $value, $type)); + $this->stmt->bindValue($param, $value, $type); } public function testCloseCursor() : void { $this->wrappedStmt->expects($this->once()) - ->method('closeCursor') - ->will($this->returnValue(true)); + ->method('closeCursor'); - self::assertTrue($this->stmt->closeCursor()); + $this->stmt->closeCursor(); } public function testColumnCount() : void @@ -85,28 +84,6 @@ public function testColumnCount() : void self::assertSame($columnCount, $this->stmt->columnCount()); } - public function testErrorCode() : void - { - $errorCode = '666'; - - $this->wrappedStmt->expects($this->once()) - ->method('errorCode') - ->will($this->returnValue($errorCode)); - - self::assertSame($errorCode, $this->stmt->errorCode()); - } - - public function testErrorInfo() : void - { - $errorInfo = ['666', 'Evil error.']; - - $this->wrappedStmt->expects($this->once()) - ->method('errorInfo') - ->will($this->returnValue($errorInfo)); - - self::assertSame($errorInfo, $this->stmt->errorInfo()); - } - public function testExecute() : void { $params = [ @@ -116,10 +93,9 @@ public function testExecute() : void $this->wrappedStmt->expects($this->once()) ->method('execute') - ->with($params) - ->will($this->returnValue(true)); + ->with($params); - self::assertTrue($this->stmt->execute($params)); + $this->stmt->execute($params); } public function testSetFetchMode() : void @@ -137,7 +113,7 @@ public function testSetFetchMode() : void $re->setAccessible(true); self::assertSame(FetchMode::MIXED, $re->getValue($this->stmt)); - self::assertTrue($this->stmt->setFetchMode($fetchMode, $arg1, $arg2)); + $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); self::assertSame($fetchMode, $re->getValue($this->stmt)); } diff --git a/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php b/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php index 0a8492f795f..b98d5f0f152 100644 --- a/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php @@ -1,5 +1,7 @@ add(null); - - self::assertCount(2, $expr); - $expr->add('u.user_id = 1'); self::assertCount(3, $expr); diff --git a/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php index 817007d67d6..52b1b0aa43b 100644 --- a/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php @@ -1,5 +1,7 @@ expr->in('u.groups', [1, 3, 4, 7])); + self::assertEquals('u.groups IN (1, 3, 4, 7)', $this->expr->in('u.groups', ['1', '3', '4', '7'])); } public function testInWithPlaceholder() : void @@ -225,7 +227,7 @@ public function testInWithPlaceholder() : void public function testNotIn() : void { - self::assertEquals('u.groups NOT IN (1, 3, 4, 7)', $this->expr->notIn('u.groups', [1, 3, 4, 7])); + self::assertEquals('u.groups NOT IN (1, 3, 4, 7)', $this->expr->notIn('u.groups', ['1', '3', '4', '7'])); } public function testNotInWithPlaceholder() : void diff --git a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php index 610abc319a9..233376890e2 100644 --- a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php @@ -1,5 +1,7 @@ conn); + $qb->update('users', 'users') + ->set('foo', '?') + ->set('bar', '?'); + + self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); + } + public function testUpdateWhere() : void { $qb = new QueryBuilder($this->conn); @@ -448,6 +460,15 @@ public function testDeleteWithoutAlias() : void self::assertEquals('DELETE FROM users', (string) $qb); } + public function testDeleteWithMatchingAlias() : void + { + $qb = new QueryBuilder($this->conn); + $qb->delete('users', 'users'); + + self::assertEquals(QueryBuilder::DELETE, $qb->getType()); + self::assertEquals('DELETE FROM users', (string) $qb); + } + public function testDeleteWhere() : void { $qb = new QueryBuilder($this->conn); @@ -652,7 +673,7 @@ public function testReferenceJoinFromJoin() : void ->where('nt.lang = :lang AND n.deleted != 1'); $this->expectException(QueryException::class); - $this->expectExceptionMessage("The given alias 'invalid' is not part of any FROM or JOIN clause table. The currently registered aliases are: news, nv."); + $this->expectExceptionMessage('The given alias "invalid" is not part of any FROM or JOIN clause table. The currently registered aliases are: news, nv.'); self::assertEquals('', $qb->getSQL()); } @@ -776,6 +797,16 @@ public function testSimpleSelectWithoutTableAlias() : void self::assertEquals('SELECT id FROM users', (string) $qb); } + public function testSimpleSelectWithMatchingTableAlias() : void + { + $qb = new QueryBuilder($this->conn); + + $qb->select('id') + ->from('users', 'users'); + + self::assertEquals('SELECT id FROM users', (string) $qb); + } + public function testSelectWithSimpleWhereWithoutTableAlias() : void { $qb = new QueryBuilder($this->conn); @@ -895,7 +926,7 @@ public function testJoinWithNonUniqueAliasThrowsException() : void ->join('a', 'table_b', 'a', 'a.fk_b = a.id'); $this->expectException(QueryException::class); - $this->expectExceptionMessage("The given alias 'a' is not unique in FROM and JOIN clause table. The currently registered aliases are: a."); + $this->expectExceptionMessage('The given alias "a" is not unique in FROM and JOIN clause table. The currently registered aliases are: a.'); $qb->getSQL(); } diff --git a/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php b/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php index ea8d4dc0752..ecbcad60906 100644 --- a/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php +++ b/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php @@ -1,5 +1,7 @@ 42, 0 => 30]], // explicit keys + ['SELECT ?', [7]], + ['SELECT * FROM Foo WHERE bar IN (?, ?, ?)', [32, 35, 38]], + ['SELECT ? FROM ?', [7, 14]], + ['SELECT "?" FROM foo', []], + ["SELECT '?' FROM foo", []], + ['SELECT `?` FROM foo', []], // Ticket DBAL-552 + ['SELECT [?] FROM foo', []], + ["SELECT 'Doctrine\DBAL?' FROM foo", []], // Ticket DBAL-558 + ['SELECT "Doctrine\DBAL?" FROM foo', []], // Ticket DBAL-558 + ['SELECT `Doctrine\DBAL?` FROM foo', []], // Ticket DBAL-558 + ['SELECT [Doctrine\DBAL?] FROM foo', []], // Ticket DBAL-558 + ['SELECT "?" FROM foo WHERE bar = ?', [32]], + ["SELECT '?' FROM foo WHERE bar = ?", [32]], + ['SELECT `?` FROM foo WHERE bar = ?', [32]], // Ticket DBAL-552 + ['SELECT [?] FROM foo WHERE bar = ?', [32]], + ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[?])', [56]], // Ticket GH-2295 + ["SELECT 'Doctrine\DBAL?' FROM foo WHERE bar = ?", [45]], // Ticket DBAL-558 + ['SELECT "Doctrine\DBAL?" FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558 + ['SELECT `Doctrine\DBAL?` FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558 + ['SELECT [Doctrine\DBAL?] FROM foo WHERE bar = ?', [45]], // Ticket DBAL-558 + ["SELECT * FROM FOO WHERE bar = 'it\\'s a trap? \\\\' OR bar = ?\nAND baz = \"\\\"quote\\\" me on it? \\\\\" OR baz = ?", [58, 104]], + ['SELECT * FROM foo WHERE foo = ? AND bar = ?', [1 => 42, 0 => 30]], // explicit keys + + ]; + } + + /** + * @return iterable> + */ + public function dataGetPlaceholderNamedPositions() : iterable + { + return [ + // none + ['SELECT * FROM Foo', []], // named - ['SELECT :foo FROM :bar', false, [7 => 'foo', 17 => 'bar']], - ['SELECT * FROM Foo WHERE bar IN (:name1, :name2)', false, [32 => 'name1', 40 => 'name2']], - ['SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', false, [37 => 'name1', 45 => 'name2']], - ["SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", false, [37 => 'name1', 45 => 'name2']], - ['SELECT :foo_id', false, [7 => 'foo_id']], // Ticket DBAL-231 - ['SELECT @rank := 1', false, []], // Ticket DBAL-398 - ['SELECT @rank := 1 AS rank, :foo AS foo FROM :bar', false, [27 => 'foo', 44 => 'bar']], // Ticket DBAL-398 - ['SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [30 => 'start_date', 52 => 'start_date']], // Ticket GH-113 - ['SELECT foo::date as date FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [46 => 'start_date', 68 => 'start_date']], // Ticket GH-259 - ['SELECT `d.ns:col_name` FROM my_table d WHERE `d.date` >= :param1', false, [57 => 'param1']], // Ticket DBAL-552 - ['SELECT [d.ns:col_name] FROM my_table d WHERE [d.date] >= :param1', false, [57 => 'param1']], // Ticket DBAL-552 - ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[:foo])', false, [56 => 'foo']], // Ticket GH-2295 - ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, array[:foo])', false, [56 => 'foo']], - ['SELECT table.field1, ARRAY[\'3\'] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']', false, [73 => 'foo']], - ['SELECT table.field1, ARRAY[\'3\']::integer[] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']::integer[]', false, [84 => 'foo']], - ['SELECT table.field1, ARRAY[:foo] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']', false, [27 => 'foo', 74 => 'bar']], - ['SELECT table.field1, ARRAY[:foo]::integer[] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']::integer[]', false, [27 => 'foo', 85 => 'bar']], + ['SELECT :foo FROM :bar', [7 => 'foo', 17 => 'bar']], + ['SELECT * FROM Foo WHERE bar IN (:name1, :name2)', [32 => 'name1', 40 => 'name2']], + ['SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', [37 => 'name1', 45 => 'name2']], + ["SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", [37 => 'name1', 45 => 'name2']], + ['SELECT :foo_id', [7 => 'foo_id']], // Ticket DBAL-231 + ['SELECT @rank := 1', []], // Ticket DBAL-398 + ['SELECT @rank := 1 AS rank, :foo AS foo FROM :bar', [27 => 'foo', 44 => 'bar']], // Ticket DBAL-398 + ['SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date', [30 => 'start_date', 52 => 'start_date']], // Ticket GH-113 + ['SELECT foo::date as date FROM Foo WHERE bar > :start_date AND baz > :start_date', [46 => 'start_date', 68 => 'start_date']], // Ticket GH-259 + ['SELECT `d.ns:col_name` FROM my_table d WHERE `d.date` >= :param1', [57 => 'param1']], // Ticket DBAL-552 + ['SELECT [d.ns:col_name] FROM my_table d WHERE [d.date] >= :param1', [57 => 'param1']], // Ticket DBAL-552 + ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[:foo])', [56 => 'foo']], // Ticket GH-2295 + ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, array[:foo])', [56 => 'foo']], + ['SELECT table.field1, ARRAY[\'3\'] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']', [73 => 'foo']], + ['SELECT table.field1, ARRAY[\'3\']::integer[] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']::integer[]', [84 => 'foo']], + ['SELECT table.field1, ARRAY[:foo] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']', [27 => 'foo', 74 => 'bar']], + ['SELECT table.field1, ARRAY[:foo]::integer[] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']::integer[]', [27 => 'foo', 85 => 'bar']], [ <<<'SQLDATA' -SELECT * FROM foo WHERE +SELECT * FROM foo WHERE bar = ':not_a_param1 ''":not_a_param2"''' OR bar=:a_param1 OR bar=:a_param2||':not_a_param3' @@ -77,18 +91,17 @@ public static function dataGetPlaceholderPositions() : iterable OR bar=:a_param3 SQLDATA , - false, [ - 74 => 'a_param1', - 91 => 'a_param2', - 190 => 'a_param3', + 73 => 'a_param1', + 90 => 'a_param2', + 189 => 'a_param3', ], ], - ["SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE '\\\\') AND (data.description LIKE :condition_1 ESCAPE '\\\\') ORDER BY id ASC", false, [121 => 'condition_0', 174 => 'condition_1']], - ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE "\\\\") ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], - ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE \'\\\\\') ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], - ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE `\\\\`) AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], - ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE \'\\\\\') AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], + ["SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE '\\\\') AND (data.description LIKE :condition_1 ESCAPE '\\\\') ORDER BY id ASC", [121 => 'condition_0', 174 => 'condition_1']], + ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE "\\\\") ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']], + ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE \'\\\\\') ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']], + ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE `\\\\`) AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']], + ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE \'\\\\\') AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', [121 => 'condition_0', 174 => 'condition_1']], ]; } @@ -96,12 +109,27 @@ public static function dataGetPlaceholderPositions() : iterable /** * @param int[] $expectedParamPos * - * @dataProvider dataGetPlaceholderPositions + * @dataProvider dataGetPlaceholderPositionalPositions */ - public function testGetPlaceholderPositions(string $query, bool $isPositional, array $expectedParamPos) : void + public function testGetPositionalPlaceholderPositions(string $query, array $expectedParamPos) : void { - $actualParamPos = SQLParserUtils::getPlaceholderPositions($query, $isPositional); - self::assertEquals($expectedParamPos, $actualParamPos); + $reflection = new ReflectionMethod(SQLParserUtils::class, 'getPositionalPlaceholderPositions'); + $reflection->setAccessible(true); + + self::assertEquals($expectedParamPos, $reflection->invoke(null, $query)); + } + + /** + * @param array $expectedParamPos + * + * @dataProvider dataGetPlaceholderNamedPositions + */ + public function testGetNamedPlaceholderPositions(string $query, array $expectedParamPos) : void + { + $reflection = new ReflectionMethod(SQLParserUtils::class, 'getNamedPlaceholderPositions'); + $reflection->setAccessible(true); + + self::assertEquals($expectedParamPos, $reflection->invoke(null, $query)); } /** @@ -491,7 +519,7 @@ public static function dataQueryWithMissingParameters() : iterable public function testExceptionIsThrownForMissingParam(string $query, array $params, array $types = []) : void { $this->expectException(SQLParserUtilsException::class); - $this->expectExceptionMessage('Value for :param not found in params array. Params array key should be "param"'); + $this->expectExceptionMessage('Parameter "param" is missing.'); SQLParserUtils::expandListParameters($query, $params, $types); } diff --git a/tests/Doctrine/Tests/DBAL/Schema/ColumnDiffTest.php b/tests/Doctrine/Tests/DBAL/Schema/ColumnDiffTest.php index 0bdaa85ef6d..a7d724cbea5 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/ColumnDiffTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/ColumnDiffTest.php @@ -1,5 +1,7 @@ diffSequence($seq1, $seq2)); self::assertTrue($c->diffSequence($seq1, $seq3)); - self::assertFalse($c->diffSequence($seq1, $seq4)); } public function testRemovedSequence() : void @@ -620,7 +620,7 @@ public function testCompareColumnCompareCaseInsensitive() : void $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); - self::assertFalse($tableDiff); + self::assertNull($tableDiff); } public function testCompareIndexBasedOnPropertiesNotName() : void @@ -648,16 +648,16 @@ public function testCompareForeignKeyBasedOnPropertiesNotName() : void { $tableA = new Table('foo'); $tableA->addColumn('id', 'integer'); - $tableA->addNamedForeignKeyConstraint('foo_constraint', 'bar', ['id'], ['id']); + $tableA->addForeignKeyConstraint('bar', ['id'], ['id'], [], 'foo_constraint'); $tableB = new Table('foo'); $tableB->addColumn('ID', 'integer'); - $tableB->addNamedForeignKeyConstraint('bar_constraint', 'bar', ['id'], ['id']); + $tableB->addForeignKeyConstraint('bar', ['id'], ['id'], [], 'bar_constraint'); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); - self::assertFalse($tableDiff); + self::assertNull($tableDiff); } public function testCompareForeignKeyRestrictNoActionAreTheSame() : void @@ -1191,7 +1191,7 @@ public function testCompareGuidColumns() : void $column2 = new Column( 'foo', Type::getType('guid'), - ['notnull' => false, 'length' => '36', 'fixed' => true, 'default' => 'NEWID()', 'comment' => 'GUID 2.'] + ['notnull' => false, 'length' => 36, 'fixed' => true, 'default' => 'NEWID()', 'comment' => 'GUID 2.'] ); self::assertEquals(['notnull', 'default', 'comment'], $comparator->diffColumn($column1, $column2)); @@ -1264,6 +1264,7 @@ public function testForeignKeyRemovalWithRenamedLocalColumn() : void 'id_table1' => new Column('id_table1', Type::getType('integer')), ], [], + [], [ new ForeignKeyConstraint(['id_table1'], 'table1', ['id'], 'fk_table2_table1'), ] @@ -1277,6 +1278,7 @@ public function testForeignKeyRemovalWithRenamedLocalColumn() : void 'id_table3' => new Column('id_table3', Type::getType('integer')), ], [], + [], [ new ForeignKeyConstraint(['id_table3'], 'table3', ['id'], 'fk_table2_table3'), ] diff --git a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php index b5744fd672d..b0d4de5f265 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php @@ -1,5 +1,7 @@ createMock(Driver::class); - $platform = $this->createMock(DB2Platform::class); - $this->conn = $this + $eventManager = new EventManager(); + $driverMock = $this->createMock(Driver::class); + $platform = $this->createMock(DB2Platform::class); + $this->conn = $this ->getMockBuilder(Connection::class) - ->setMethods(['fetchAll', 'quote']) + ->setMethods(['fetchAll']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); + $this->manager = new DB2SchemaManager($this->conn); } @@ -43,30 +47,9 @@ protected function setUp() : void */ public function testListTableNamesFiltersAssetNamesCorrectly() : void { - $this->conn->getConfiguration()->setFilterSchemaAssetsExpression('/^(?!T_)/'); - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ - ['name' => 'FOO'], - ['name' => 'T_FOO'], - ['name' => 'BAR'], - ['name' => 'T_BAR'], - ])); - - self::assertSame( - [ - 'FOO', - 'BAR', - ], - $this->manager->listTableNames() - ); - } - - /** - * @group DBAL-2701 - */ - public function testAssetFilteringSetsACallable() : void - { - $filterExpression = '/^(?!T_)/'; - $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); + $this->conn->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool { + return preg_match('/^(?!T_)/', $name) === 1; + }); $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], @@ -81,12 +64,6 @@ public function testAssetFilteringSetsACallable() : void ], $this->manager->listTableNames() ); - - $callable = $this->conn->getConfiguration()->getSchemaAssetsFilter(); - self::assertIsCallable($callable); - - // BC check: Test that regexp expression is still preserved & accessible. - $this->assertEquals($filterExpression, $this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); } public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() : void @@ -95,68 +72,8 @@ public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() : voi $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { return in_array($assetName, $accepted); }); - $this->conn->expects($this->any())->method('quote'); - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ - ['name' => 'FOO'], - ['name' => 'T_FOO'], - ['name' => 'BAR'], - ['name' => 'T_BAR'], - ])); - - self::assertSame( - [ - 'T_FOO', - 'T_BAR', - ], - $this->manager->listTableNames() - ); - - $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); - } - - public function testSettingNullExpressionWillResetCallable() : void - { - $accepted = ['T_FOO', 'T_BAR']; - $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { - return in_array($assetName, $accepted); - }); - $this->conn->expects($this->any())->method('quote'); - $this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([ - ['name' => 'FOO'], - ['name' => 'T_FOO'], - ['name' => 'BAR'], - ['name' => 'T_BAR'], - ])); - - self::assertSame( - [ - 'T_FOO', - 'T_BAR', - ], - $this->manager->listTableNames() - ); - - $this->conn->getConfiguration()->setFilterSchemaAssetsExpression(null); - - self::assertSame( - [ - 'FOO', - 'T_FOO', - 'BAR', - 'T_BAR', - ], - $this->manager->listTableNames() - ); - $this->assertNull($this->conn->getConfiguration()->getSchemaAssetsFilter()); - } - - public function testSettingNullAsCallableClearsExpression() : void - { - $filterExpression = '/^(?!T_)/'; - $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); - - $this->conn->expects($this->exactly(2))->method('fetchAll')->will($this->returnValue([ + $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], @@ -165,24 +82,10 @@ public function testSettingNullAsCallableClearsExpression() : void self::assertSame( [ - 'FOO', - 'BAR', - ], - $this->manager->listTableNames() - ); - - $this->conn->getConfiguration()->setSchemaAssetsFilter(null); - - self::assertSame( - [ - 'FOO', 'T_FOO', - 'BAR', 'T_BAR', ], $this->manager->listTableNames() ); - - $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); } } diff --git a/tests/Doctrine/Tests/DBAL/Schema/ForeignKeyConstraintTest.php b/tests/Doctrine/Tests/DBAL/Schema/ForeignKeyConstraintTest.php index f0b115ddc4f..f1f5c6aa05e 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/ForeignKeyConstraintTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/ForeignKeyConstraintTest.php @@ -1,5 +1,7 @@ setPrimaryKey(['bar_id', 'foo_id']); $diff = $this->comparator->diffTable($tableOld, $tableNew); - $sql = $this->platform->getAlterTableSQL($diff); + + self::assertNotNull($diff); + + $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals( [ @@ -51,7 +56,7 @@ public function testGenerateForeignKeySQL() : void { $tableOld = new Table('test'); $tableOld->addColumn('foo_id', 'integer'); - $tableOld->addUnnamedForeignKeyConstraint('test_foreign', ['foo_id'], ['foo_id']); + $tableOld->addForeignKeyConstraint('test_foreign', ['foo_id'], ['foo_id']); $sqls = []; foreach ($tableOld->getForeignKeys() as $fk) { @@ -74,7 +79,10 @@ public function testClobNoAlterTable() : void $tableNew->setPrimaryKey(['id']); $diff = $this->comparator->diffTable($tableOld, $tableNew); - $sql = $this->platform->getAlterTableSQL($diff); + + self::assertNotNull($diff); + + $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals( ['ALTER TABLE test ADD PRIMARY KEY (id)'], diff --git a/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php b/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php index 87146c2f001..383ff1c6c3a 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php @@ -1,5 +1,7 @@ newNamespaces['foo_ns'] = 'foo_ns'; $diff->removedNamespaces['bar_ns'] = 'bar_ns'; - $diff->changedSequences['foo_seq'] = new Sequence('foo_seq'); - $diff->newSequences['bar_seq'] = new Sequence('bar_seq'); - $diff->removedSequences['baz_seq'] = new Sequence('baz_seq'); + $diff->changedSequences[] = new Sequence('foo_seq'); + $diff->newSequences[] = new Sequence('bar_seq'); + $diff->removedSequences[] = new Sequence('baz_seq'); $diff->newTables['foo_table'] = new Table('foo_table'); $diff->removedTables['bar_table'] = new Table('bar_table'); $diff->changedTables['baz_table'] = new TableDiff('baz_table'); diff --git a/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php b/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php index 69796236235..ae94fc98e61 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php @@ -1,5 +1,7 @@ expects($this->exactly(2)) ->method('acceptSequence'); - self::assertNull($schema->visit($visitor)); + $schema->visit($visitor); } /** @@ -460,6 +462,8 @@ public function testVisitsNamespaceVisitor() : void $visitor->expects($this->exactly(2)) ->method('acceptSequence'); - self::assertNull($schema->visit($visitor)); + $schema->visit($visitor); + + self::doesNotPerformAssertions(); // FIXME } } diff --git a/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php b/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php index d13d0a908a6..e1ad3941379 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php @@ -1,5 +1,7 @@ getNewName()); + self::assertNull($tableDiff->getNewName()); $tableDiff->newName = 'bar'; diff --git a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php index 6b5145934a8..6ca2a24dd3b 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/TableTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/TableTest.php @@ -1,5 +1,7 @@ getForeignKeys(); self::assertCount(1, $constraints); - self::assertSame($constraint, array_shift($constraints)); + + $constraintNames = array_keys($constraints); + + self::assertSame('fk_8c736521', $constraintNames[0]); + self::assertSame($constraint, $constraints['fk_8c736521']); } public function testOptions() : void { - $table = new Table('foo', [], [], [], false, ['foo' => 'bar']); + $table = new Table('foo', [], [], [], [], ['foo' => 'bar']); self::assertTrue($table->hasOption('foo')); self::assertEquals('bar', $table->getOption('foo')); @@ -885,4 +892,33 @@ public static function getNormalizesAssetNames() : iterable ['"FOO"'], ]; } + + public function testUniqueConstraintWithEmptyName() : void + { + $columns = [ + new Column('column1', Type::getType(Type::STRING)), + new Column('column2', Type::getType(Type::STRING)), + new Column('column3', Type::getType(Type::STRING)), + new Column('column4', Type::getType(Type::STRING)), + ]; + + $uniqueConstraints = [ + new UniqueConstraint('', ['column1', 'column2']), + new UniqueConstraint('', ['column3', 'column4']), + ]; + + $table = new Table('test', $columns, [], $uniqueConstraints); + + $constraints = $table->getUniqueConstraints(); + + self::assertCount(2, $constraints); + + $constraintNames = array_keys($constraints); + + self::assertSame('fk_d87f7e0c341ce00bad15b1b1', $constraintNames[0]); + self::assertSame('fk_d87f7e0cda12812744761484', $constraintNames[1]); + + self::assertSame($uniqueConstraints[0], $constraints['fk_d87f7e0c341ce00bad15b1b1']); + self::assertSame($uniqueConstraints[1], $constraints['fk_d87f7e0cda12812744761484']); + } } diff --git a/tests/Doctrine/Tests/DBAL/Schema/Visitor/CreateSchemaSqlCollectorTest.php b/tests/Doctrine/Tests/DBAL/Schema/Visitor/CreateSchemaSqlCollectorTest.php index b70d2193a37..cd173df6bb1 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/Visitor/CreateSchemaSqlCollectorTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/Visitor/CreateSchemaSqlCollectorTest.php @@ -1,5 +1,7 @@ PoolingShardConnection::class, + $conn = $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -27,6 +31,8 @@ public function testConnect() : void 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertFalse($conn->isConnected(0)); $conn->connect(0); self::assertEquals(1, $conn->fetchColumn('SELECT 1')); @@ -50,11 +56,10 @@ public function testConnect() : void public function testNoGlobalServerException() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Connection Parameters require "global" and "shards" configurations.'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'shards' => [ ['id' => 1, 'memory' => true], @@ -66,11 +71,10 @@ public function testNoGlobalServerException() : void public function testNoShardsServersException() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Connection Parameters require "global" and "shards" configurations.'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shardChoser' => MultiTenantShardChoser::class, @@ -79,11 +83,10 @@ public function testNoShardsServersException() : void public function testNoShardsChoserException() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Missing Shard Choser configuration 'shardChoser'"); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Missing Shard Choser configuration "shardChoser".'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -95,11 +98,10 @@ public function testNoShardsChoserException() : void public function testShardChoserWrongInstance() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "shardChoser" configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -115,8 +117,7 @@ public function testShardNonNumericId() : void $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Shard Id has to be a non-negative number.'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -128,11 +129,10 @@ public function testShardNonNumericId() : void public function testShardMissingId() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Missing 'id' for one configured shard. Please specify a unique shard-id."); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Missing "id" for one configured shard. Please specify a unique shard-id.'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -144,11 +144,10 @@ public function testShardMissingId() : void public function testDuplicateShardId() : void { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Shard 1 is duplicated in the configuration.'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Shard "1" is duplicated in the configuration.'); - DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -161,8 +160,7 @@ public function testDuplicateShardId() : void public function testSwitchShardWithOpenTransactionException() : void { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $conn = $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -171,6 +169,8 @@ public function testSwitchShardWithOpenTransactionException() : void 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + $conn->beginTransaction(); $this->expectException(ShardingException::class); @@ -180,8 +180,7 @@ public function testSwitchShardWithOpenTransactionException() : void public function testGetActiveShardId() : void { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $conn = $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ @@ -190,6 +189,8 @@ public function testGetActiveShardId() : void 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertNull($conn->getActiveShardId()); $conn->connect(0); @@ -204,8 +205,7 @@ public function testGetActiveShardId() : void public function testGetParamsOverride() : void { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, + $conn = $this->createConnection([ 'driver' => 'pdo_sqlite', 'global' => ['memory' => true, 'host' => 'localhost'], 'shards' => [ @@ -214,6 +214,8 @@ public function testGetParamsOverride() : void 'shardChoser' => MultiTenantShardChoser::class, ]); + assert($conn instanceof PoolingShardConnection); + self::assertEquals([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', @@ -241,79 +243,18 @@ public function testGetParamsOverride() : void ], $conn->getParams()); } - public function testGetHostOverride() : void + /** + * @param array $parameters + */ + private function createConnection(array $parameters) : PoolingShardConnection { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'host' => 'localhost', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'host' => 'foo'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); + $connection = DriverManager::getConnection(array_merge( + ['wrapperClass' => PoolingShardConnection::class], + $parameters + )); - self::assertEquals('localhost', $conn->getHost()); + self::assertInstanceOf(PoolingShardConnection::class, $connection); - $conn->connect(1); - self::assertEquals('foo', $conn->getHost()); - } - - public function testGetPortOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'port' => 3306, - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'port' => 3307], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals(3306, $conn->getPort()); - - $conn->connect(1); - self::assertEquals(3307, $conn->getPort()); - } - - public function testGetUsernameOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'user' => 'foo', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'user' => 'bar'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals('foo', $conn->getUsername()); - - $conn->connect(1); - self::assertEquals('bar', $conn->getUsername()); - } - - public function testGetPasswordOverride() : void - { - $conn = DriverManager::getConnection([ - 'wrapperClass' => PoolingShardConnection::class, - 'driver' => 'pdo_sqlite', - 'password' => 'foo', - 'global' => ['memory' => true], - 'shards' => [ - ['id' => 1, 'memory' => true, 'password' => 'bar'], - ], - 'shardChoser' => MultiTenantShardChoser::class, - ]); - - self::assertEquals('foo', $conn->getPassword()); - - $conn->connect(1); - self::assertEquals('bar', $conn->getPassword()); + return $connection; } } diff --git a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php index 01db26773f3..114b27ca824 100644 --- a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php @@ -1,5 +1,7 @@ createConnectionMock(); - $conn->expects($this->once())->method('connect')->with($this->equalTo(0)); + $conn->expects($this->at(0)) + ->method('getParams') + ->will( + $this->returnValue([ + 'shardChoser' => $this->createMock(ShardChoser::class), + ]) + ); + $conn->expects($this->at(1))->method('connect')->with($this->equalTo(0)); $shardManager = new PoolingShardManager($conn); $shardManager->selectGlobal(); diff --git a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php index b0439d5dfe2..ef36ada364a 100644 --- a/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php @@ -1,5 +1,7 @@ pdoStatement = $this->getMockBuilder(PDOStatement::class) - ->setMethods(['execute', 'bindParam', 'bindValue']) - ->getMock(); + $this->driverStatement = $this->createMock(DriverStatement::class); - $driverConnection = $this->createMock(DriverConnection::class); - $driverConnection->expects($this->any()) - ->method('prepare') - ->will($this->returnValue($this->pdoStatement)); + $driverConnection = $this->createConfiguredMock(DriverConnection::class, [ + 'prepare' => $this->driverStatement, + ]); $driver = $this->createMock(Driver::class); @@ -140,7 +140,7 @@ public function testExecuteCallsLoggerStopQueryOnException() : void $logger->expects($this->once()) ->method('stopQuery'); - $this->pdoStatement->expects($this->once()) + $this->driverStatement->expects($this->once()) ->method('execute') ->will($this->throwException(new Exception('Mock test exception'))); diff --git a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php index 21eab4203ba..ab11e47f33f 100644 --- a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php +++ b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php @@ -1,11 +1,14 @@ commandTester->execute([ - 'command' => $this->command->getName(), - 'sql' => null, - ]); - $this->fail('Expected a runtime exception when omitting sql argument'); - } catch (RuntimeException $e) { - self::assertStringContainsString("Argument 'SQL", $e->getMessage()); - } + self::expectException(RuntimeException::class); + self::expectExceptionMessage('Argument "sql" is required in order to execute this command correctly.'); + + $this->commandTester->execute([ + 'command' => $this->command->getName(), + 'sql' => null, + ]); } public function testIncorrectDepthOption() : void { - try { - $this->commandTester->execute([ - 'command' => $this->command->getName(), - 'sql' => 'SELECT 1', - '--depth' => 'string', - ]); - $this->fail('Expected a logic exception when executing with a stringy depth'); - } catch (LogicException $e) { - self::assertStringContainsString("Option 'depth'", $e->getMessage()); - } + self::expectException(LogicException::class); + self::expectExceptionMessage('Option "depth" must contains an integer value.'); + + $this->commandTester->execute([ + 'command' => $this->command->getName(), + 'sql' => 'SELECT 1', + '--depth' => 'string', + ]); } public function testSelectStatementsPrintsResult() : void diff --git a/tests/Doctrine/Tests/DBAL/Tools/DumperTest.php b/tests/Doctrine/Tests/DBAL/Tools/DumperTest.php index ba99024231b..e6f95b93af8 100644 --- a/tests/Doctrine/Tests/DBAL/Tools/DumperTest.php +++ b/tests/Doctrine/Tests/DBAL/Tools/DumperTest.php @@ -1,5 +1,7 @@ expectException(ConversionException::class); - $this->expectExceptionMessage("Could not convert database value to 'array' as an error was triggered by the unserialization: 'unserialize(): Error at offset 0 of 7 bytes'"); + $this->expectExceptionMessage('Could not convert database value to "array" as an error was triggered by the unserialization: unserialize(): Error at offset 0 of 7 bytes'); $this->type->convertToPHPValue('abcdefg', $this->platform); } diff --git a/tests/Doctrine/Tests/DBAL/Types/BaseDateTypeTestCase.php b/tests/Doctrine/Tests/DBAL/Types/BaseDateTypeTestCase.php index 5f5b412e249..6e1e2ace82b 100644 --- a/tests/Doctrine/Tests/DBAL/Types/BaseDateTypeTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Types/BaseDateTypeTestCase.php @@ -1,5 +1,7 @@ type->getName()); } - public function testReturnsSQLDeclaration() : void + /** + * @param mixed[][] $definition + * + * @dataProvider definitionProvider() + */ + public function testReturnsSQLDeclaration(array $definition, string $expectedDeclaration) : void { - $this->platform->expects($this->once()) - ->method('getBinaryTypeDeclarationSQL') - ->willReturn('TEST_BINARY'); + $platform = $this->getMockForAbstractClass(AbstractPlatform::class); + self::assertSame($expectedDeclaration, $this->type->getSQLDeclaration($definition, $platform)); + } - self::assertSame('TEST_BINARY', $this->type->getSQLDeclaration([], $this->platform)); + /** + * @return mixed[][] + */ + public static function definitionProvider() : iterable + { + return [ + 'fixed-unspecified-length' => [ + ['fixed' => true], + 'BINARY', + ], + 'fixed-specified-length' => [ + [ + 'fixed' => true, + 'length' => 20, + ], + 'BINARY(20)', + ], + 'variable-length' => [ + ['length' => 20], + 'VARBINARY(20)', + ], + ]; } public function testBinaryNullConvertsToPHPValue() : void @@ -57,11 +87,10 @@ public function testBinaryNullConvertsToPHPValue() : void public function testBinaryStringConvertsToPHPValue() : void { - $databaseValue = 'binary string'; + $databaseValue = $this->getBinaryString(); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - self::assertIsResource($phpValue); - self::assertEquals($databaseValue, stream_get_contents($phpValue)); + self::assertSame($databaseValue, $phpValue); } public function testBinaryResourceConvertsToPHPValue() : void @@ -69,7 +98,15 @@ public function testBinaryResourceConvertsToPHPValue() : void $databaseValue = fopen('data://text/plain;base64,' . base64_encode('binary string'), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - self::assertSame($databaseValue, $phpValue); + self::assertSame('binary string', $phpValue); + } + + /** + * Creates a binary string containing all possible byte values. + */ + private function getBinaryString() : string + { + return implode(array_map('chr', range(0, 255))); } /** diff --git a/tests/Doctrine/Tests/DBAL/Types/BlobTest.php b/tests/Doctrine/Tests/DBAL/Types/BlobTest.php index 194d26af0b8..f31369e6fd6 100644 --- a/tests/Doctrine/Tests/DBAL/Types/BlobTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/BlobTest.php @@ -1,5 +1,7 @@ type->convertToPHPValue(null, $this->platform)); } - - public function testBinaryStringConvertsToPHPValue() : void - { - $databaseValue = $this->getBinaryString(); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertIsResource($phpValue); - self::assertSame($databaseValue, stream_get_contents($phpValue)); - } - - public function testBinaryResourceConvertsToPHPValue() : void - { - $databaseValue = fopen('data://text/plain;base64,' . base64_encode($this->getBinaryString()), 'r'); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertSame($databaseValue, $phpValue); - } - - /** - * Creates a binary string containing all possible byte values. - */ - private function getBinaryString() : string - { - $string = ''; - - for ($i = 0; $i < 256; $i++) { - $string .= chr($i); - } - - return $string; - } } diff --git a/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php b/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php index b5e25c2a77b..0c012b83c94 100644 --- a/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php @@ -1,5 +1,7 @@ getMessage() ); } @@ -34,12 +47,13 @@ public function testConversionFailedInvalidTypeWithScalar($scalarValue) : void */ public function testConversionFailedInvalidTypeWithNonScalar($nonScalar) : void { - $exception = ConversionException::conversionFailedInvalidType($nonScalar, 'foo', ['bar', 'baz']); + $exception = InvalidType::new($nonScalar, 'foo', ['bar', 'baz']); + + $type = is_object($nonScalar) ? get_class($nonScalar) : gettype($nonScalar); self::assertInstanceOf(ConversionException::class, $exception); - self::assertRegExp( - '/^Could not convert PHP value of type \'(.*)\' to type \'foo\'. ' - . 'Expected one of the following types: bar, baz$/', + self::assertSame( + sprintf('Could not convert PHP value of type "%s" to type "foo". Expected one of the following types: bar, baz.', $type), $exception->getMessage() ); } @@ -48,7 +62,7 @@ public function testConversionFailedFormatPreservesPreviousException() : void { $previous = new Exception(); - $exception = ConversionException::conversionFailedFormat('foo', 'bar', 'baz', $previous); + $exception = InvalidFormat::new('foo', 'bar', 'baz', $previous); self::assertInstanceOf(ConversionException::class, $exception); self::assertSame($previous, $exception->getPrevious()); diff --git a/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php index c48f9a5ee34..7d383f46a8c 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php @@ -1,5 +1,7 @@ type = Type::getType('date_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() : void @@ -44,46 +46,53 @@ public function testReturnsBindingType() : void public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->createMock(DateTimeImmutable::class); - $this->platform->getDateFormatString()->willReturn('Y-m-d')->shouldBeCalled(); - $date->format('Y-m-d')->willReturn('2016-01-01')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d') + ->willReturn('2016-01-01'); self::assertSame( '2016-01-01', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateStringToPHPValue() : void { - $this->platform->getDateFormatString()->willReturn('Y-m-d')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); - $date = $this->type->convertToPHPValue('2016-01-01', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01', $date->format('Y-m-d')); @@ -91,9 +100,11 @@ public function testConvertsDateStringToPHPValue() : void public function testResetTimeFractionsWhenConvertingToPHPValue() : void { - $this->platform->getDateFormatString()->willReturn('Y-m-d'); + $this->platform->expects($this->any()) + ->method('getDateFormatString') + ->willReturn('Y-m-d'); - $date = $this->type->convertToPHPValue('2016-01-01', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertSame('2016-01-01 00:00:00.000000', $date->format('Y-m-d H:i:s.u')); } @@ -102,11 +113,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateStri { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid date string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid date string', $this->platform); } public function testRequiresSQLCommentHint() : void { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/DateIntervalTest.php b/tests/Doctrine/Tests/DBAL/Types/DateIntervalTest.php index 7b2c09aca9f..67b534a4b58 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateIntervalTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateIntervalTest.php @@ -1,5 +1,7 @@ type = Type::getType('datetime_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() : void @@ -44,46 +46,53 @@ public function testReturnsBindingType() : void public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); - $date->format('Y-m-d H:i:s')->willReturn('2016-01-01 15:58:59')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s') + ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeStringToPHPValue() : void { - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); @@ -94,22 +103,28 @@ public function testConvertsDateTimeStringToPHPValue() : void */ public function testConvertsDateTimeStringWithMicrosecondsToPHPValue() : void { - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s'); + $this->platform->expects($this->any()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456', $this->platform); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeString() : void { + $this->platform->expects($this->atLeastOnce()) + ->method('getDateTimeFormatString') + ->willReturn('Y-m-d H:i:s'); + $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid datetime string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid datetime string', $this->platform); } public function testRequiresSQLCommentHint() : void { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php index ba7a661c8d9..34df91b0f4e 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php @@ -1,5 +1,7 @@ type = Type::getType('datetimetz_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() : void @@ -44,46 +46,53 @@ public function testReturnsBindingType() : void public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->createMock(DateTimeImmutable::class); - $this->platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); - $date->format('Y-m-d H:i:s T')->willReturn('2016-01-01 15:58:59 UTC')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s T') + ->willReturn('2016-01-01 15:58:59 UTC'); self::assertSame( '2016-01-01 15:58:59 UTC', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeWithTimezoneStringToPHPValue() : void { - $this->platform->getDateTimeTzFormatString()->willReturn('Y-m-d H:i:s T')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59 UTC', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59 UTC', $date->format('Y-m-d H:i:s T')); @@ -91,13 +100,17 @@ public function testConvertsDateTimeWithTimezoneStringToPHPValue() : void public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeWithTimezoneString() : void { + $this->platform->expects($this->atLeastOnce()) + ->method('getDateTimeTzFormatString') + ->willReturn('Y-m-d H:i:s T'); + $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform); } public function testRequiresSQLCommentHint() : void { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php index 72ccaf87d05..d380f75b196 100644 --- a/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php @@ -1,5 +1,7 @@ getMessage() + ); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Types/Exception/TypeAlreadyRegisteredTest.php b/tests/Doctrine/Tests/DBAL/Types/Exception/TypeAlreadyRegisteredTest.php new file mode 100644 index 00000000000..29074c56b75 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Types/Exception/TypeAlreadyRegisteredTest.php @@ -0,0 +1,22 @@ +getMessage()) === 1); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Types/Exception/TypeNotRegisteredTest.php b/tests/Doctrine/Tests/DBAL/Types/Exception/TypeNotRegisteredTest.php new file mode 100644 index 00000000000..844814d448b --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Types/Exception/TypeNotRegisteredTest.php @@ -0,0 +1,22 @@ +getMessage()) === 1); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Types/FloatTest.php b/tests/Doctrine/Tests/DBAL/Types/FloatTest.php index 4934f716c0f..962cd98c458 100644 --- a/tests/Doctrine/Tests/DBAL/Types/FloatTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/FloatTest.php @@ -1,5 +1,7 @@ platform = $this->createMock(AbstractPlatform::class); - $this->type = Type::getType('json_array'); - } - - public function testReturnsBindingType() : void - { - self::assertSame(ParameterType::STRING, $this->type->getBindingType()); - } - - public function testReturnsName() : void - { - self::assertSame(Types::JSON_ARRAY, $this->type->getName()); - } - - public function testReturnsSQLDeclaration() : void - { - $this->platform->expects($this->once()) - ->method('getJsonTypeDeclarationSQL') - ->willReturn('TEST_JSON'); - - self::assertSame('TEST_JSON', $this->type->getSQLDeclaration([], $this->platform)); - } - - public function testJsonNullConvertsToPHPValue() : void - { - self::assertSame([], $this->type->convertToPHPValue(null, $this->platform)); - } - - public function testJsonEmptyStringConvertsToPHPValue() : void - { - self::assertSame([], $this->type->convertToPHPValue('', $this->platform)); - } - - public function testJsonStringConvertsToPHPValue() : void - { - $value = ['foo' => 'bar', 'bar' => 'foo']; - $databaseValue = json_encode($value); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertEquals($value, $phpValue); - } - - public function testJsonResourceConvertsToPHPValue() : void - { - $value = ['foo' => 'bar', 'bar' => 'foo']; - $databaseValue = fopen('data://text/plain;base64,' . base64_encode(json_encode($value)), 'r'); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); - - self::assertSame($value, $phpValue); - } - - public function testRequiresSQLCommentHint() : void - { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Types/JsonTest.php b/tests/Doctrine/Tests/DBAL/Types/JsonTest.php index 4a5ff3c28c0..92393abbd52 100644 --- a/tests/Doctrine/Tests/DBAL/Types/JsonTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/JsonTest.php @@ -1,5 +1,7 @@ 'bar', 'bar' => 'foo']; - $databaseValue = json_encode($value); - $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); + $value = ['foo' => 'bar', 'bar' => 'foo']; + + $databaseValue = '{"foo":"bar","bar":"foo"}'; + + $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertEquals($value, $phpValue); } @@ -86,8 +89,11 @@ public static function providerFailure() : iterable public function testJsonResourceConvertsToPHPValue() : void { - $value = ['foo' => 'bar', 'bar' => 'foo']; - $databaseValue = fopen('data://text/plain;base64,' . base64_encode(json_encode($value)), 'r'); + $value = ['foo' => 'bar', 'bar' => 'foo']; + + $json = '{"foo":"bar","bar":"foo"}'; + + $databaseValue = fopen('data://text/plain;base64,' . base64_encode($json), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertSame($value, $phpValue); diff --git a/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php b/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php index da9481d105a..a1c249e75e4 100644 --- a/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php @@ -1,5 +1,7 @@ expectException(ConversionException::class); - $this->expectExceptionMessage("Could not convert database value to 'object' as an error was triggered by the unserialization: 'unserialize(): Error at offset 0 of 7 bytes'"); + $this->expectExceptionMessage('Could not convert database value to "object" as an error was triggered by the unserialization: unserialize(): Error at offset 0 of 7 bytes'); + $this->type->convertToPHPValue('abcdefg', $this->platform); } diff --git a/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php b/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php index b1731a99578..77bbe2d3246 100644 --- a/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php @@ -1,5 +1,7 @@ type = Type::getType('string'); } - public function testReturnsSqlDeclarationFromPlatformVarchar() : void + public function testReturnsSQLDeclaration() : void { $this->platform->expects($this->once()) - ->method('getVarcharTypeDeclarationSQL') + ->method('getStringTypeDeclarationSQL') ->willReturn('TEST_VARCHAR'); self::assertEquals('TEST_VARCHAR', $this->type->getSqlDeclaration([], $this->platform)); } - public function testReturnsDefaultLengthFromPlatformVarchar() : void - { - $this->platform->expects($this->once()) - ->method('getVarcharDefaultLength') - ->willReturn(255); - - self::assertEquals(255, $this->type->getDefaultLength($this->platform)); - } - public function testConvertToPHPValue() : void { self::assertIsString($this->type->convertToPHPValue('foo', $this->platform)); diff --git a/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php index e1445bee90c..dfd0a0d0e97 100644 --- a/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php @@ -1,5 +1,7 @@ type = Type::getType('time_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() : void @@ -44,46 +46,53 @@ public function testReturnsBindingType() : void public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getTimeFormatString()->willReturn('H:i:s')->shouldBeCalled(); - $date->format('H:i:s')->willReturn('15:58:59')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); + $date->expects($this->once()) + ->method('format') + ->with('H:i:s') + ->willReturn('15:58:59'); self::assertSame( '15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsTimeStringToPHPValue() : void { - $this->platform->getTimeFormatString()->willReturn('H:i:s')->shouldBeCalled(); + $this->platform->expects($this->once()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); - $date = $this->type->convertToPHPValue('15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('15:58:59', $date->format('H:i:s')); @@ -91,9 +100,11 @@ public function testConvertsTimeStringToPHPValue() : void public function testResetDateFractionsWhenConvertingToPHPValue() : void { - $this->platform->getTimeFormatString()->willReturn('H:i:s'); + $this->platform->expects($this->any()) + ->method('getTimeFormatString') + ->willReturn('H:i:s'); - $date = $this->type->convertToPHPValue('15:58:59', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertSame('1970-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } @@ -102,11 +113,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidTimeStri { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid time string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid time string', $this->platform); } public function testRequiresSQLCommentHint() : void { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/TimeTest.php b/tests/Doctrine/Tests/DBAL/Types/TimeTest.php index a75544b650e..f2c89d095b6 100644 --- a/tests/Doctrine/Tests/DBAL/Types/TimeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/TimeTest.php @@ -1,5 +1,7 @@ registry->lookupName($this->otherTestType) ); - $this->expectException(DBALException::class); + $this->expectException(TypeNotRegistered::class); $this->registry->lookupName(new TextType()); } diff --git a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php index 9786c46bb1c..83133a885de 100644 --- a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php @@ -1,5 +1,7 @@ type = Type::getType('vardatetime_immutable'); - $this->platform = $this->prophesize(AbstractPlatform::class); + $this->platform = $this->getMockForAbstractClass(AbstractPlatform::class); } public function testReturnsName() : void @@ -42,46 +44,46 @@ public function testReturnsBindingType() : void public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { - $date = $this->prophesize(DateTimeImmutable::class); + $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); - $this->platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s')->shouldBeCalled(); - $date->format('Y-m-d H:i:s')->willReturn('2016-01-01 15:58:59')->shouldBeCalled(); + $date->expects($this->once()) + ->method('format') + ->with('Y-m-d H:i:s') + ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', - $this->type->convertToDatabaseValue($date->reveal(), $this->platform->reveal()) + $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { - self::assertNull($this->type->convertToDatabaseValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new DateTime(), $this->platform->reveal()); + $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform->reveal())); + self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { - self::assertNull($this->type->convertToPHPValue(null, $this->platform->reveal())); + self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateishStringToPHPValue() : void { - $this->platform->getDateTimeFormatString()->shouldNotBeCalled(); - - $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456 UTC', $this->platform->reveal()); + $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59.123456 UTC', $date->format('Y-m-d H:i:s.u T')); @@ -91,11 +93,11 @@ public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateishS { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('invalid date-ish string', $this->platform->reveal()); + $this->type->convertToPHPValue('invalid date-ish string', $this->platform); } public function testRequiresSQLCommentHint() : void { - self::assertTrue($this->type->requiresSQLCommentHint($this->platform->reveal())); + self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } diff --git a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php index 7fe10cb2ba3..6051b5b5790 100644 --- a/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php +++ b/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php @@ -1,5 +1,7 @@ platform = $this->createMock(AbstractPlatform::class); + $this->platform->expects($this->any()) + ->method('getDateTimeFormatString') + ->will($this->returnValue('U')); + if (! Type::hasType('vardatetime')) { Type::addType('vardatetime', VarDateTimeType::class); } @@ -31,7 +37,7 @@ public function testDateTimeConvertsToDatabaseValue() : void { $date = new DateTime('1985-09-01 10:10:10'); - $expected = $date->format($this->platform->getDateTimeTzFormatString()); + $expected = $date->format($this->platform->getDateTimeFormatString()); $actual = $this->type->convertToDatabaseValue($date, $this->platform); self::assertEquals($expected, $actual); diff --git a/tests/Doctrine/Tests/DBAL/UtilTest.php b/tests/Doctrine/Tests/DBAL/UtilTest.php index 92f63872f15..a70f638ca2b 100644 --- a/tests/Doctrine/Tests/DBAL/UtilTest.php +++ b/tests/Doctrine/Tests/DBAL/UtilTest.php @@ -1,5 +1,7 @@ getDatabase(); $realConn->close(); + if ($dbname === null) { + throw new InvalidArgumentException( + 'You must have a database configured in your connection.' + ); + } + $tmpConn->getSchemaManager()->dropAndCreateDatabase($dbname); $tmpConn->close(); @@ -160,7 +169,7 @@ private static function getParamsForTemporaryConnection() : array 'password' => $GLOBALS['tmpdb_password'], 'host' => $GLOBALS['tmpdb_host'], 'dbname' => null, - 'port' => $GLOBALS['tmpdb_port'], + 'port' => (int) $GLOBALS['tmpdb_port'], ]; if (isset($GLOBALS['tmpdb_name'])) { @@ -189,7 +198,7 @@ private static function getParamsForMainConnection() : array 'password' => $GLOBALS['db_password'], 'host' => $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], - 'port' => $GLOBALS['db_port'], + 'port' => (int) $GLOBALS['db_port'], ]; if (isset($GLOBALS['db_server'])) { diff --git a/tests/Doctrine/Tests/Types/CommentedType.php b/tests/Doctrine/Tests/Types/CommentedType.php index cbe98b2324b..a59cd4e234d 100644 --- a/tests/Doctrine/Tests/Types/CommentedType.php +++ b/tests/Doctrine/Tests/Types/CommentedType.php @@ -1,5 +1,7 @@ getName()); } @@ -27,7 +29,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritDoc} */ - public function requiresSQLCommentHint(AbstractPlatform $platform) + public function requiresSQLCommentHint(AbstractPlatform $platform) : bool { return true; } diff --git a/tests/Doctrine/Tests/Types/MySqlPointType.php b/tests/Doctrine/Tests/Types/MySqlPointType.php index f4740769b8b..e810c67108b 100644 --- a/tests/Doctrine/Tests/Types/MySqlPointType.php +++ b/tests/Doctrine/Tests/Types/MySqlPointType.php @@ -1,5 +1,7 @@ getName()); } @@ -27,7 +29,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritDoc} */ - public function getMappedDatabaseTypes(AbstractPlatform $platform) + public function getMappedDatabaseTypes(AbstractPlatform $platform) : array { return ['point']; } diff --git a/tests/continuousphp/bootstrap.php b/tests/continuousphp/bootstrap.php index 9f6b0971a79..b7d22fa1d1f 100644 --- a/tests/continuousphp/bootstrap.php +++ b/tests/continuousphp/bootstrap.php @@ -20,6 +20,8 @@ return; } + assert(is_int($pos)); + $file = $_SERVER['argv'][$pos + 1]; register_shutdown_function(static function () use ($file) : void {