From 3fe4d3cf0fd75986d9de37e3212386cc534bf65d Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 22 May 2020 21:41:53 -0700 Subject: [PATCH 1/9] Update slevomat/coding-standard to 6.3.6 --- composer.json | 1 + composer.lock | 16 ++++++++-------- .../Tests/DBAL/Driver/StatementIteratorTest.php | 6 ++++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index eb5f95c8eb0..a2d8ede2829 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,7 @@ "nikic/php-parser": "^4.4", "phpstan/phpstan": "^0.12", "phpunit/phpunit": "^8.4.1", + "slevomat/coding-standard": "^6.3.6", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", "vimeo/psalm": "^3.11" }, diff --git a/composer.lock b/composer.lock index 0073213a8c6..d626f4ec2f6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6bf4905b268231ccd58bdbe30d4ecf81", + "content-hash": "ae54b78f0088f88dbcfa8e179be7c43b", "packages": [ { "name": "doctrine/cache", @@ -2416,16 +2416,16 @@ }, { "name": "slevomat/coding-standard", - "version": "6.3.3", + "version": "6.3.6", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b905a82255749de847fd4de607c7a4c8163f058d" + "reference": "7876032a4f55acf2de2cf3cd538feaf98a8a0fee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b905a82255749de847fd4de607c7a4c8163f058d", - "reference": "b905a82255749de847fd4de607c7a4c8163f058d", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7876032a4f55acf2de2cf3cd538feaf98a8a0fee", + "reference": "7876032a4f55acf2de2cf3cd538feaf98a8a0fee", "shasum": "" }, "require": { @@ -2469,7 +2469,7 @@ "type": "tidelift" } ], - "time": "2020-04-28T07:15:08+00:00" + "time": "2020-05-22T15:11:14+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -2920,8 +2920,8 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", diff --git a/tests/Doctrine/Tests/DBAL/Driver/StatementIteratorTest.php b/tests/Doctrine/Tests/DBAL/Driver/StatementIteratorTest.php index b3d8abc6b85..c65db5ecc05 100644 --- a/tests/Doctrine/Tests/DBAL/Driver/StatementIteratorTest.php +++ b/tests/Doctrine/Tests/DBAL/Driver/StatementIteratorTest.php @@ -97,8 +97,10 @@ public static function statementProvider() : iterable yield [PortabilityStatement::class]; yield [SQLAnywhereStatement::class]; - if (extension_loaded('sqlsrv')) { - yield [SQLSrvStatement::class]; + if (! extension_loaded('sqlsrv')) { + return; } + + yield [SQLSrvStatement::class]; } } From 5af3709a1a407429120611f8e843de4b22a149a3 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 22 May 2020 16:19:17 -0700 Subject: [PATCH 2/9] Deprecated the concept of the fetch mode --- UPGRADE.md | 10 + lib/Doctrine/DBAL/Cache/ArrayStatement.php | 78 +++++- .../DBAL/Cache/ResultCacheStatement.php | 118 ++++++++- lib/Doctrine/DBAL/Connection.php | 229 ++++++++++++++++++ lib/Doctrine/DBAL/Driver/FetchUtils.php | 61 +++++ .../DBAL/Driver/IBMDB2/DB2Statement.php | 10 + .../DBAL/Driver/Mysqli/MysqliStatement.php | 80 +++++- .../DBAL/Driver/OCI8/OCI8Statement.php | 93 ++++++- .../DBAL/Driver/PDOSqlsrv/Connection.php | 5 + lib/Doctrine/DBAL/Driver/PDOStatement.php | 51 +++- lib/Doctrine/DBAL/Driver/ResultStatement.php | 8 + .../SQLAnywhere/SQLAnywhereConnection.php | 17 +- .../SQLAnywhere/SQLAnywhereStatement.php | 69 +++++- .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 5 + .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 68 +++++- .../DBAL/Driver/StatementIterator.php | 3 + lib/Doctrine/DBAL/FetchMode.php | 2 + .../Driver/ResultStatement.php | 59 +++++ .../ForwardCompatibility/ResultStatement.php | 42 ++++ lib/Doctrine/DBAL/Id/TableGenerator.php | 4 +- lib/Doctrine/DBAL/Portability/Statement.php | 142 +++++++++-- .../DBAL/Schema/AbstractSchemaManager.php | 16 +- lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 4 +- .../DBAL/Schema/MySqlSchemaManager.php | 2 +- .../DBAL/Schema/OracleSchemaManager.php | 4 +- .../DBAL/Schema/PostgreSqlSchemaManager.php | 3 +- .../DBAL/Schema/SQLServerSchemaManager.php | 6 +- .../DBAL/Schema/SqliteSchemaManager.php | 15 +- .../DBAL/Sharding/PoolingShardManager.php | 2 +- .../SQLAzure/SQLAzureShardManager.php | 4 +- lib/Doctrine/DBAL/Statement.php | 177 +++++++++++++- .../Tools/Console/Command/RunSqlCommand.php | 2 +- .../BackwardCompatibility/Connection.php | 37 +++ .../BackwardCompatibility/FetchTest.php | 23 ++ .../BackwardCompatibility/Statement.php | 158 ++++++++++++ .../DBAL/Functional/Connection/FetchTest.php | 114 +++++++++ .../DBAL/Schema/DB2SchemaManagerTest.php | 12 +- .../DBAL/Schema/MySqlSchemaManagerTest.php | 14 +- .../DBAL/Sharding/PoolingShardManagerTest.php | 10 +- .../DBAL/Tools/Console/RunSqlCommandTest.php | 12 +- tests/Doctrine/Tests/TestUtil.php | 26 ++ 41 files changed, 1714 insertions(+), 81 deletions(-) create mode 100644 lib/Doctrine/DBAL/Driver/FetchUtils.php create mode 100644 lib/Doctrine/DBAL/ForwardCompatibility/Driver/ResultStatement.php create mode 100644 lib/Doctrine/DBAL/ForwardCompatibility/ResultStatement.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Connection.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/FetchTest.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Statement.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php diff --git a/UPGRADE.md b/UPGRADE.md index a6d4c85004e..1a5b80cafdc 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,15 @@ # Upgrade to 2.11 +## Deprecated `FetchMode` and the corresponding methods + +1. The `FetchMode` class and the `setFetchMode()` method of the `Connection` and `Statement` interfaces are deprecated. +2. The `Statement::fetch()` method is deprecated in favor of `fetchNumeric()`, `fetchAssociative()` and `fetchOne()`. +3. The `Statement::fetchAll()` method is deprecated in favor of `fetchAllNumeric()` and `fetchAllAssociative()`. There is no currently replacement for `Statement::fetchAll(FETCH_MODE::COLUMN)`. In a future major version, `fetchColumn()` will be used as a replacement. +4. The `Statement::fetchColumn()` method is deprecated in favor of `fetchOne()`. +5. The `Connection::fetchArray()` and `fetchAssoc()` method are deprecated in favor of `fetchNumeric()` and `fetchAssociative()` respectively. +6. The `StatementIterator` class and the usage of a `Statement` object as `Traversable` is deprecated in favor of `iterateNumeric()`, `iterateAssociative()` and `iterateColumn()`. +7. Fetching data in mixed mode (`FetchMode::MIXED`) is deprecated. + ## Deprecated `Connection::project()` The `Connection::project()` method is deprecated. Implement data transformation outside of DBAL. diff --git a/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/lib/Doctrine/DBAL/Cache/ArrayStatement.php index 5b72e599ac3..1e17b766e27 100644 --- a/lib/Doctrine/DBAL/Cache/ArrayStatement.php +++ b/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -3,8 +3,10 @@ namespace Doctrine\DBAL\Cache; use ArrayIterator; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use InvalidArgumentException; use IteratorAggregate; use PDO; @@ -13,7 +15,7 @@ use function count; use function reset; -class ArrayStatement implements IteratorAggregate, ResultStatement +class ArrayStatement implements IteratorAggregate, ResultStatement, ForwardCompatibleResultStatement { /** @var mixed[] */ private $data; @@ -60,6 +62,8 @@ public function columnCount() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -74,6 +78,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -84,6 +90,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -115,6 +123,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -128,6 +138,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -136,4 +148,68 @@ public function fetchColumn($columnIndex = 0) // TODO: verify that return false is the correct behavior return $row[$columnIndex] ?? false; } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return array_values($row); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return reset($row); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * @return mixed|false + */ + private function doFetch() + { + if (! isset($this->data[$this->num])) { + return false; + } + + return $this->data[$this->num++]; + } } diff --git a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php index cbb44a94a1a..1a4382dd178 100644 --- a/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +++ b/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -4,9 +4,12 @@ use ArrayIterator; use Doctrine\Common\Cache\Cache; +use Doctrine\DBAL\Driver\DriverException; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use InvalidArgumentException; use IteratorAggregate; use PDO; @@ -28,7 +31,7 @@ * Also you have to realize that the cache will load the whole result into memory at once to ensure 2. * This means that the memory usage for cached results might increase by using this feature. */ -class ResultCacheStatement implements IteratorAggregate, ResultStatement +class ResultCacheStatement implements IteratorAggregate, ResultStatement, ForwardCompatibleResultStatement { /** @var Cache */ private $resultCache; @@ -105,6 +108,8 @@ public function columnCount() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -115,6 +120,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -125,6 +132,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -165,6 +174,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -184,6 +195,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -193,6 +206,64 @@ public function fetchColumn($columnIndex = 0) return $row[$columnIndex] ?? false; } + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + $row = $this->doFetch(); + + if ($row === false) { + return false; + } + + return array_values($row); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + if ($this->statement instanceof ForwardCompatibleResultStatement) { + $data = $this->statement->fetchAllAssociative(); + } else { + $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); + } + + return $this->store($data); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + if ($this->statement instanceof ForwardCompatibleResultStatement) { + $data = $this->statement->fetchAllAssociative(); + } else { + $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); + } + + return $this->store($data); + } + /** * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement * executed by the corresponding object. @@ -210,4 +281,49 @@ public function rowCount() return $this->statement->rowCount(); } + + /** + * @return array|false + * + * @throws DriverException + */ + private function doFetch() + { + if ($this->data === null) { + $this->data = []; + } + + if ($this->statement instanceof ForwardCompatibleResultStatement) { + $row = $this->statement->fetchAssociative(); + } else { + $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); + } + + if ($row !== false) { + $this->data[] = $row; + + return $row; + } + + $this->emptied = true; + + return false; + } + + /** + * @param array> $data + * + * @return array> + */ + private function store(array $data) : array + { + foreach ($data as $key => $value) { + $data[$key] = [$value]; + } + + $this->data = $data; + $this->emptied = true; + + return $this->data; + } } diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index f49ba0ba951..c4f0c3727d0 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -14,6 +14,7 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Exception\InvalidArgumentException; +use Doctrine\DBAL\ForwardCompatibility\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Doctrine\DBAL\Query\QueryBuilder; @@ -21,6 +22,7 @@ use Doctrine\DBAL\Types\Type; use Exception; use Throwable; +use Traversable; use function array_key_exists; use function assert; use function func_get_args; @@ -529,6 +531,8 @@ public function setAutoCommit($autoCommit) /** * Sets the fetch mode. * + * @deprecated Use one of the fetch- or iterate-related methods. + * * @param int $fetchMode * * @return void @@ -542,6 +546,8 @@ public function setFetchMode($fetchMode) * Prepares and executes an SQL query and returns the first row of the result * as an associative array. * + * @deprecated Use fetchAllAssociative() + * * @param string $statement The SQL query. * @param mixed[] $params The query parameters. * @param int[]|string[] $types The query parameter types. @@ -559,6 +565,8 @@ public function fetchAssoc($statement, array $params = [], array $types = []) * Prepares and executes an SQL query and returns the first row of the result * as a numerically indexed array. * + * @deprecated Use fetchAllNumeric() + * * @param string $statement The SQL query to be executed. * @param mixed[] $params The prepared statement params. * @param int[]|string[] $types The query parameter types. @@ -574,6 +582,8 @@ public function fetchArray($statement, array $params = [], array $types = []) * Prepares and executes an SQL query and returns the value of a single column * of the first row of the result. * + * @deprecated Use fetchOne() instead. + * * @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. @@ -588,6 +598,87 @@ public function fetchColumn($statement, array $params = [], $column = 0, array $ return $this->executeQuery($statement, $params, $types)->fetchColumn($column); } + /** + * Prepares and executes an SQL query and returns the first row of the result + * as an associative array. + * + * @param string $query The SQL query. + * @param array|array $params The prepared statement params. + * @param array|array $types The query parameter types. + * + * @return array|false False is returned if no rows are found. + * + * @throws DBALException + */ + public function fetchAssociative(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchAssociative(); + } + + return $stmt->fetch(FetchMode::ASSOCIATIVE); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as a numerically indexed array. + * + * @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 array|false False is returned if no rows are found. + * + * @throws DBALException + */ + public function fetchNumeric(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchNumeric(); + } + + return $stmt->fetch(FetchMode::NUMERIC); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the value of a single column + * of the first row of the result. + * + * @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. + * + * @throws DBALException + */ + public function fetchOne(string $query, array $params = [], array $types = []) + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchOne(); + } + + return $stmt->fetch(FetchMode::COLUMN); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + /** * Whether an actual connection to the database is established. * @@ -835,6 +926,8 @@ public function quote($input, $type = ParameterType::STRING) /** * Prepares and executes an SQL query and returns the result as an associative array. * + * @deprecated Use fetchAllAssociative() + * * @param string $sql The SQL query. * @param mixed[] $params The query parameters. * @param int[]|string[] $types The query parameter types. @@ -846,6 +939,142 @@ public function fetchAll($sql, array $params = [], $types = []) return $this->executeQuery($sql, $params, $types)->fetchAll(); } + /** + * Prepares and executes an SQL query and returns the result as an array of numeric arrays. + * + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. + * + * @return array> + * + * @throws DBALException + */ + public function fetchAllNumeric(string $query, array $params = [], array $types = []) : array + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchAllNumeric(); + } + + return $stmt->fetchAll(FetchMode::NUMERIC); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an array of associative arrays. + * + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. + * + * @return array> + * + * @throws DBALException + */ + public function fetchAllAssociative(string $query, array $params = [], array $types = []) : array + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchAllAssociative(); + } + + return $stmt->fetchAll(FetchMode::ASSOCIATIVE); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over rows represented as numeric arrays. + * + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateNumeric(string $query, array $params = [], array $types = []) : Traversable + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + yield from $stmt->iterateNumeric(); + } else { + while (($row = $stmt->fetch(FetchMode::NUMERIC)) !== false) { + yield $row; + } + } + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over rows represented as associative arrays. + * + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateAssociative(string $query, array $params = [], array $types = []) : Traversable + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + yield from $stmt->iterateAssociative(); + } else { + while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield $row; + } + } + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + + /** + * Prepares and executes an SQL query and returns the result as an iterator over the first column values. + * + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. + * + * @return Traversable + * + * @throws DBALException + */ + public function iterateColumn(string $query, array $params = [], array $types = []) : Traversable + { + try { + $stmt = $this->executeQuery($query, $params, $types); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + yield from $stmt->iterateColumn(); + } else { + while (($value = $stmt->fetch(FetchMode::COLUMN)) !== false) { + yield $value; + } + } + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } + } + /** * Prepares an SQL statement. * diff --git a/lib/Doctrine/DBAL/Driver/FetchUtils.php b/lib/Doctrine/DBAL/Driver/FetchUtils.php new file mode 100644 index 00000000000..358429255f0 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/FetchUtils.php @@ -0,0 +1,61 @@ +fetchNumeric(); + + if ($row === false) { + return false; + } + + return $row[0]; + } + + /** + * @return array> + * + * @throws DriverException + */ + public static function fetchAllNumeric(ResultStatement $stmt) : array + { + $rows = []; + + while (($row = $stmt->fetchNumeric()) !== false) { + $rows[] = $row; + } + + return $rows; + } + + /** + * @return array> + * + * @throws DriverException + */ + public static function fetchAllAssociative(ResultStatement $stmt) : array + { + $rows = []; + + while (($row = $stmt->fetchAssociative()) !== false) { + $rows[] = $row; + } + + return $rows; + } +} diff --git a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php index eb30651fc51..3a01b3ad9d1 100644 --- a/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php +++ b/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -232,6 +232,8 @@ public function execute($params = null) /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -244,6 +246,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -252,6 +256,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -303,6 +309,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -334,6 +342,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 738bd8e1b4f..9a3c76ce55d 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -2,10 +2,12 @@ namespace Doctrine\DBAL\Driver\Mysqli; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\Exception\InvalidArgumentException; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use IteratorAggregate; use mysqli; @@ -24,7 +26,7 @@ use function sprintf; use function str_repeat; -class MysqliStatement implements IteratorAggregate, Statement +class MysqliStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement { /** @var string[] */ protected static $_paramTypeMap = [ @@ -307,6 +309,8 @@ private function _fetch() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -357,6 +361,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -379,6 +385,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -396,6 +404,72 @@ public function fetchColumn($columnIndex = 0) * * @deprecated The error information is available via exceptions. */ + public function fetchNumeric() + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + $values = $this->_fetch(); + + if ($values === null) { + return false; + } + + if ($values === false) { + throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); + } + + return $values; + } + + /** + * {@inheritDoc} + */ + public function fetchAssociative() + { + $values = $this->fetchNumeric(); + + if ($values === false) { + return false; + } + + assert(is_array($this->_columnNames)); + $row = array_combine($this->_columnNames, $values); + assert(is_array($row)); + + return $row; + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return FetchUtils::fetchAllAssociative($this); + } + + /** + * {@inheritdoc} + */ public function errorCode() { return $this->_stmt->errno; @@ -444,6 +518,8 @@ public function columnCount() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -454,6 +530,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { diff --git a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index d64f55919d1..1be74545b2a 100644 --- a/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -2,9 +2,11 @@ namespace Doctrine\DBAL\Driver\OCI8; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use InvalidArgumentException; use IteratorAggregate; @@ -47,7 +49,7 @@ /** * The OCI8 implementation of the Statement interface. */ -class OCI8Statement implements IteratorAggregate, Statement +class OCI8Statement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement { /** @var resource */ protected $_dbh; @@ -410,6 +412,8 @@ public function execute($params = null) /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -420,6 +424,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -428,6 +434,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -459,6 +467,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -513,6 +523,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -538,4 +550,83 @@ public function rowCount() { return oci_num_rows($this->_sth) ?: 0; } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->doFetch(OCI_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(OCI_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + return $this->doFetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return $this->doFetchAll(OCI_ASSOC, OCI_FETCHSTATEMENT_BY_ROW); + } + + /** + * @return mixed|false + */ + private function doFetch(int $mode) + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return false; + } + + return oci_fetch_array( + $this->_sth, + $mode | OCI_RETURN_NULLS | OCI_RETURN_LOBS + ); + } + + /** + * @return array + */ + private function doFetchAll(int $mode, int $fetchStructure) : array + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if (! $this->result) { + return []; + } + + oci_fetch_all( + $this->_sth, + $result, + 0, + -1, + $mode | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS + ); + + return $result; + } } diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php index bd3894477b5..56cca064068 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -3,6 +3,7 @@ namespace Doctrine\DBAL\Driver\PDOSqlsrv; use Doctrine\DBAL\Driver\PDOConnection; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use PDO; use function strpos; @@ -34,6 +35,10 @@ public function lastInsertId($name = null) $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); $stmt->execute([$name]); + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchOne(); + } + return $stmt->fetchColumn(); } diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index c7db7d4eb87..1922c4c0e3a 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -3,6 +3,7 @@ namespace Doctrine\DBAL\Driver; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use PDO; use function array_slice; @@ -17,7 +18,7 @@ * The PDO implementation of the Statement interface. * Used by all PDO-based drivers. */ -class PDOStatement extends \PDOStatement implements Statement +class PDOStatement extends \PDOStatement implements Statement, ForwardCompatibleResultStatement { private const PARAM_TYPE_MAP = [ ParameterType::NULL => PDO::PARAM_NULL, @@ -46,6 +47,8 @@ protected function __construct() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -132,6 +135,8 @@ public function execute($params = null) /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -150,6 +155,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -181,6 +188,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -191,6 +200,46 @@ public function fetchColumn($columnIndex = 0) } } + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->fetch(PDO::FETCH_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->fetch(PDO::FETCH_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return $this->fetch(PDO::FETCH_COLUMN); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + return $this->fetchAll(PDO::FETCH_NUM); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return $this->fetchAll(PDO::FETCH_ASSOC); + } + /** * Converts DBAL parameter type to PDO parameter type * diff --git a/lib/Doctrine/DBAL/Driver/ResultStatement.php b/lib/Doctrine/DBAL/Driver/ResultStatement.php index 1e6df0269b8..c48e0e28400 100644 --- a/lib/Doctrine/DBAL/Driver/ResultStatement.php +++ b/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -29,6 +29,8 @@ public function columnCount(); /** * Sets the fetch mode to use while iterating this statement. * + * @deprecated Use one of the fetch- or iterate-related methods. + * * @param int $fetchMode The fetch mode must be one of the {@link \Doctrine\DBAL\FetchMode} constants. * @param mixed $arg2 * @param mixed $arg3 @@ -40,6 +42,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null); /** * Returns the next row of a result set. * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * * @param int|null $fetchMode Controls how the next row will be returned to the caller. * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. @@ -67,6 +71,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * Returns an array containing all of the result set rows. * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. + * * @param int|null $fetchMode Controls how the next row will be returned to the caller. * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. @@ -89,6 +95,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * Returns a single column from the next row of a result set or FALSE if there are no more rows. * + * @deprecated Use fetchOne() instead. + * * @param int $columnIndex 0-indexed number of the column you wish to retrieve from the row. * If no value is supplied, fetches the first column. * diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php index cca9df5fac0..37d99c328be 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use function assert; use function func_get_args; @@ -125,7 +126,13 @@ public function exec($statement) */ public function getServerVersion() { - $version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchColumn(); + $stmt = $this->query("SELECT PROPERTY('ProductVersion')"); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + $version = $stmt->fetchOne(); + } else { + $version = $stmt->fetchColumn(); + } assert(is_string($version)); @@ -141,7 +148,13 @@ public function lastInsertId($name = null) return sasql_insert_id($this->connection); } - return $this->query('SELECT ' . $name . '.CURRVAL')->fetchColumn(); + $stmt = $this->query('SELECT ' . $name . '.CURRVAL'); + + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchOne(); + } + + return $stmt->fetchColumn(); } /** diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index c5d8e5d9eee..74e9b5745ab 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -2,9 +2,12 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere; +use Doctrine\DBAL\Driver\DriverException; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use IteratorAggregate; use PDO; @@ -39,7 +42,7 @@ /** * SAP SQL Anywhere implementation of the Statement interface. */ -class SQLAnywhereStatement implements IteratorAggregate, Statement +class SQLAnywhereStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement { /** @var resource The connection resource. */ private $conn; @@ -201,6 +204,8 @@ public function execute($params = null) /** * {@inheritdoc} * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * * @throws SQLAnywhereException */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) @@ -252,6 +257,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -283,6 +290,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -297,12 +306,68 @@ public function fetchColumn($columnIndex = 0) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { return new StatementIterator($this); } + /** + * {@inheritDoc} + */ + public function fetchNumeric() + { + if (! is_resource($this->result)) { + return false; + } + + return sasql_fetch_row($this->result); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + if (! is_resource($this->result)) { + return false; + } + + return sasql_fetch_assoc($this->result); + } + + /** + * {@inheritdoc} + * + * @throws DriverException + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * @return array> + * + * @throws DriverException + */ + public function fetchAllNumeric() : array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * @return array> + * + * @throws DriverException + */ + public function fetchAllAssociative() : array + { + return FetchUtils::fetchAllAssociative($this); + } + /** * {@inheritdoc} */ @@ -313,6 +378,8 @@ public function rowCount() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php index 6c8864fa03a..b5b0f0518e8 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use function func_get_args; use function is_float; @@ -141,6 +142,10 @@ public function lastInsertId($name = null) $stmt = $this->query('SELECT @@IDENTITY'); } + if ($stmt instanceof ForwardCompatibleResultStatement) { + return $stmt->fetchOne(); + } + return $stmt->fetchColumn(); } diff --git a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php index 956b497aa95..8292a62c311 100644 --- a/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -2,9 +2,11 @@ namespace Doctrine\DBAL\Driver\SQLSrv; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use IteratorAggregate; use PDO; @@ -38,7 +40,7 @@ /** * SQL Server Statement. */ -class SQLSrvStatement implements IteratorAggregate, Statement +class SQLSrvStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement { /** * The SQLSRV Resource. @@ -322,6 +324,8 @@ private function prepare() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -334,6 +338,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -343,6 +349,8 @@ public function getIterator() /** * {@inheritdoc} * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * * @throws SQLSrvException */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) @@ -381,6 +389,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -412,6 +422,8 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { @@ -424,6 +436,46 @@ public function fetchColumn($columnIndex = 0) return $row[$columnIndex] ?? null; } + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + return $this->doFetch(SQLSRV_FETCH_NUMERIC); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + return $this->doFetch(SQLSRV_FETCH_ASSOC); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + return FetchUtils::fetchOne($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + return FetchUtils::fetchAllNumeric($this); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return FetchUtils::fetchAllAssociative($this); + } + /** * {@inheritdoc} */ @@ -435,4 +487,18 @@ public function rowCount() return sqlsrv_rows_affected($this->stmt) ?: 0; } + + /** + * @return mixed|false + */ + private function doFetch(int $fetchType) + { + // do not try fetching from the statement if it's not expected to contain the result + // in order to prevent exceptional situation + if ($this->stmt === null || ! $this->result) { + return false; + } + + return sqlsrv_fetch_array($this->stmt, $fetchType) ?? false; + } } diff --git a/lib/Doctrine/DBAL/Driver/StatementIterator.php b/lib/Doctrine/DBAL/Driver/StatementIterator.php index 6b3307da2af..cb1ac3a6253 100644 --- a/lib/Doctrine/DBAL/Driver/StatementIterator.php +++ b/lib/Doctrine/DBAL/Driver/StatementIterator.php @@ -4,6 +4,9 @@ use IteratorAggregate; +/** + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn(). + */ class StatementIterator implements IteratorAggregate { /** @var ResultStatement */ diff --git a/lib/Doctrine/DBAL/FetchMode.php b/lib/Doctrine/DBAL/FetchMode.php index b3fe42f4ceb..440bd12e673 100644 --- a/lib/Doctrine/DBAL/FetchMode.php +++ b/lib/Doctrine/DBAL/FetchMode.php @@ -6,6 +6,8 @@ /** * Contains statement fetch modes. + * + * @deprecated Use one of the fetch- or iterate-related methods on the Statement. */ final class FetchMode { diff --git a/lib/Doctrine/DBAL/ForwardCompatibility/Driver/ResultStatement.php b/lib/Doctrine/DBAL/ForwardCompatibility/Driver/ResultStatement.php new file mode 100644 index 00000000000..ef0f88bd511 --- /dev/null +++ b/lib/Doctrine/DBAL/ForwardCompatibility/Driver/ResultStatement.php @@ -0,0 +1,59 @@ +|false + * + * @throws DriverException + */ + public function fetchNumeric(); + + /** + * Returns the next row of a result set as an associative array or FALSE if there are no more rows. + * + * @return array|false + * + * @throws DriverException + */ + public function fetchAssociative(); + + /** + * Returns the first value of the next row of a result set or FALSE if there are no more rows. + * + * @return mixed|false + * + * @throws DriverException + */ + public function fetchOne(); + + /** + * Returns an array containing all of the result set rows represented as numeric arrays. + * + * @return array> + * + * @throws DriverException + */ + public function fetchAllNumeric() : array; + + /** + * Returns an array containing all of the result set rows represented as associative arrays. + * + * @return array> + * + * @throws DriverException + */ + public function fetchAllAssociative() : array; +} diff --git a/lib/Doctrine/DBAL/ForwardCompatibility/ResultStatement.php b/lib/Doctrine/DBAL/ForwardCompatibility/ResultStatement.php new file mode 100644 index 00000000000..2ba19fa5324 --- /dev/null +++ b/lib/Doctrine/DBAL/ForwardCompatibility/ResultStatement.php @@ -0,0 +1,42 @@ +> + * + * @throws DBALException + */ + public function iterateNumeric() : Traversable; + + /** + * Returns an iterator over the result set rows represented as associative arrays. + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateAssociative() : Traversable; + + /** + * Returns an iterator over the values of the first column of the result set. + * + * @return Traversable + * + * @throws DBALException + */ + public function iterateColumn() : Traversable; +} diff --git a/lib/Doctrine/DBAL/Id/TableGenerator.php b/lib/Doctrine/DBAL/Id/TableGenerator.php index 97bc70282f3..e3b4c4d2ee6 100644 --- a/lib/Doctrine/DBAL/Id/TableGenerator.php +++ b/lib/Doctrine/DBAL/Id/TableGenerator.php @@ -5,7 +5,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\LockMode; use Throwable; use function array_change_key_case; @@ -105,8 +104,7 @@ public function nextValue($sequenceName) $sql = 'SELECT sequence_value, sequence_increment_by' . ' FROM ' . $platform->appendLockHint($this->generatorTableName, LockMode::PESSIMISTIC_WRITE) . ' WHERE sequence_name = ? ' . $platform->getWriteLockSQL(); - $stmt = $this->conn->executeQuery($sql, [$sequenceName]); - $row = $stmt->fetch(FetchMode::ASSOCIATIVE); + $row = $this->conn->fetchAssociative($sql, [$sequenceName]); if ($row !== false) { $row = array_change_key_case($row, CASE_LOWER); diff --git a/lib/Doctrine/DBAL/Portability/Statement.php b/lib/Doctrine/DBAL/Portability/Statement.php index 96727b2448a..d2ad241d099 100644 --- a/lib/Doctrine/DBAL/Portability/Statement.php +++ b/lib/Doctrine/DBAL/Portability/Statement.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\FetchMode; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use IteratorAggregate; use PDO; @@ -17,7 +18,7 @@ /** * Portability wrapper for a Statement. */ -class Statement implements IteratorAggregate, DriverStatement +class Statement implements IteratorAggregate, DriverStatement, ForwardCompatibleResultStatement { /** @var int */ private $portability; @@ -115,6 +116,8 @@ public function execute($params = null) /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) { @@ -125,6 +128,8 @@ public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) /** * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. */ public function getIterator() { @@ -133,6 +138,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -140,7 +147,7 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX $row = $this->stmt->fetch($fetchMode); - $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); @@ -152,6 +159,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -163,37 +172,138 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n $rows = $this->stmt->fetchAll($fetchMode); } - $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); - $fixCase = $this->case !== null + $fixCase = $this->case !== null && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) && ($this->portability & Connection::PORTABILITY_FIX_CASE); + return $this->fixResultSet($rows, $fixCase, $fetchMode !== FetchMode::COLUMN); + } + + /** + * {@inheritdoc} + */ + public function fetchNumeric() + { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + $row = $this->stmt->fetchNumeric(); + } else { + $row = $this->stmt->fetch(FetchMode::NUMERIC); + } + + return $this->fixResult($row, false); + } + + /** + * {@inheritdoc} + */ + public function fetchAssociative() + { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + $row = $this->stmt->fetchAssociative(); + } else { + $row = $this->stmt->fetch(FetchMode::ASSOCIATIVE); + } + + return $this->fixResult($row, true); + } + + /** + * {@inheritdoc} + */ + public function fetchOne() + { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + $value = $this->stmt->fetchOne(); + } else { + $value = $this->stmt->fetch(FetchMode::COLUMN); + } + + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $value === '') { + $value = null; + } elseif (($this->portability & Connection::PORTABILITY_RTRIM) !== 0 && is_string($value)) { + $value = rtrim($value); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function fetchAllNumeric() : array + { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + $data = $this->stmt->fetchAllNumeric(); + } else { + $data = $this->stmt->fetchAll(FetchMode::NUMERIC); + } + + return $this->fixResultSet($data, false, true); + } + + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + $data = $this->stmt->fetchAllAssociative(); + } else { + $data = $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); + } + + return $this->fixResultSet($data, true, true); + } + + /** + * @param mixed $result + * + * @return mixed + */ + private function fixResult($result, bool $fixCase) + { + $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0; + $fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0; + + return $this->fixRow($result, $iterateRow, $fixCase); + } + + /** + * @param array $resultSet + * + * @return array + */ + private function fixResultSet(array $resultSet, bool $fixCase, bool $isArray) : array + { + $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0; + $fixCase = $fixCase && $this->case !== null && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0; + if (! $iterateRow && ! $fixCase) { - return $rows; + return $resultSet; } - if ($fetchMode === FetchMode::COLUMN) { - foreach ($rows as $num => $row) { - $rows[$num] = [$row]; + if (! $isArray) { + foreach ($resultSet as $num => $value) { + $resultSet[$num] = [$value]; } } - foreach ($rows as $num => $row) { - $rows[$num] = $this->fixRow($row, $iterateRow, $fixCase); + foreach ($resultSet as $num => $row) { + $resultSet[$num] = $this->fixRow($row, $iterateRow, $fixCase); } - if ($fetchMode === FetchMode::COLUMN) { - foreach ($rows as $num => $row) { - $rows[$num] = $row[0]; + if (! $isArray) { + foreach ($resultSet as $num => $row) { + $resultSet[$num] = $row[0]; } } - return $rows; + return $resultSet; } /** * @param mixed $row - * @param int $iterateRow + * @param bool $iterateRow * @param bool $fixCase * * @return mixed @@ -223,6 +333,8 @@ protected function fixRow($row, $iterateRow, $fixCase) /** * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index b90994e0e64..c1c23cdae5b 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -101,7 +101,7 @@ public function listDatabases() { $sql = $this->_platform->getListDatabasesSQL(); - $databases = $this->_conn->fetchAll($sql); + $databases = $this->_conn->fetchAllAssociative($sql); return $this->_getPortableDatabasesList($databases); } @@ -115,7 +115,7 @@ public function listNamespaceNames() { $sql = $this->_platform->getListNamespacesSQL(); - $namespaces = $this->_conn->fetchAll($sql); + $namespaces = $this->_conn->fetchAllAssociative($sql); return $this->getPortableNamespacesList($namespaces); } @@ -135,7 +135,7 @@ public function listSequences($database = null) $sql = $this->_platform->getListSequencesSQL($database); - $sequences = $this->_conn->fetchAll($sql); + $sequences = $this->_conn->fetchAllAssociative($sql); return $this->filterAssetNames($this->_getPortableSequencesList($sequences)); } @@ -163,7 +163,7 @@ public function listTableColumns($table, $database = null) $sql = $this->_platform->getListTableColumnsSQL($table, $database); - $tableColumns = $this->_conn->fetchAll($sql); + $tableColumns = $this->_conn->fetchAllAssociative($sql); return $this->_getPortableTableColumnList($table, $database, $tableColumns); } @@ -181,7 +181,7 @@ public function listTableIndexes($table) { $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); - $tableIndexes = $this->_conn->fetchAll($sql); + $tableIndexes = $this->_conn->fetchAllAssociative($sql); return $this->_getPortableTableIndexesList($tableIndexes, $table); } @@ -211,7 +211,7 @@ public function listTableNames() { $sql = $this->_platform->getListTablesSQL(); - $tables = $this->_conn->fetchAll($sql); + $tables = $this->_conn->fetchAllAssociative($sql); $tableNames = $this->_getPortableTablesList($tables); return $this->filterAssetNames($tableNames); @@ -289,7 +289,7 @@ public function listViews() { $database = $this->_conn->getDatabase(); $sql = $this->_platform->getListViewsSQL($database); - $views = $this->_conn->fetchAll($sql); + $views = $this->_conn->fetchAllAssociative($sql); return $this->_getPortableViewsList($views); } @@ -309,7 +309,7 @@ public function listTableForeignKeys($table, $database = null) } $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); - $tableForeignKeys = $this->_conn->fetchAll($sql); + $tableForeignKeys = $this->_conn->fetchAllAssociative($sql); return $this->_getPortableTableForeignKeysList($tableForeignKeys); } diff --git a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php index d2d6cef0743..60f95cb9cea 100644 --- a/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -30,7 +30,7 @@ public function listTableNames() $sql = $this->_platform->getListTablesSQL(); $sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')'; - $tables = $this->_conn->fetchAll($sql); + $tables = $this->_conn->fetchAllAssociative($sql); return $this->filterAssetNames($this->_getPortableTablesList($tables)); } @@ -228,7 +228,7 @@ public function listTableDetails($tableName) : Table assert($platform instanceof DB2Platform); $sql = $platform->getListTableCommentsSQL($tableName); - $tableOptions = $this->_conn->fetchAssoc($sql); + $tableOptions = $this->_conn->fetchAssociative($sql); if ($tableOptions !== false) { $table->addOption('comment', $tableOptions['REMARKS']); diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php index 15866efae9e..cd469f38c6a 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -326,7 +326,7 @@ public function listTableDetails($tableName) assert($platform instanceof MySqlPlatform); $sql = $platform->getListTableMetadataSQL($tableName); - $tableOptions = $this->_conn->fetchAssoc($sql); + $tableOptions = $this->_conn->fetchAssociative($sql); if ($tableOptions === false) { return $table; diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index e2816caeb00..108ae4d53e9 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -380,7 +380,7 @@ private function killUserSessions($user) AND p.addr(+) = s.paddr SQL; - $activeUserSessions = $this->_conn->fetchAll($sql, [strtoupper($user)]); + $activeUserSessions = $this->_conn->fetchAllAssociative($sql, [strtoupper($user)]); foreach ($activeUserSessions as $activeUserSession) { $activeUserSession = array_change_key_case($activeUserSession, CASE_LOWER); @@ -406,7 +406,7 @@ public function listTableDetails($tableName) : Table assert($platform instanceof OraclePlatform); $sql = $platform->getListTableCommentsSQL($tableName); - $tableOptions = $this->_conn->fetchAssoc($sql); + $tableOptions = $this->_conn->fetchAssociative($sql); if ($tableOptions !== false) { $table->addOption('comment', $tableOptions['COMMENTS']); diff --git a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php index 287a7dac6ba..ceeb99d84c3 100644 --- a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -221,8 +221,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null implode(' ,', $colNumbers) ); - $stmt = $this->_conn->executeQuery($columnNameSql); - $indexColumns = $stmt->fetchAll(); + $indexColumns = $this->_conn->fetchAllAssociative($columnNameSql); // required for getting the order of the columns right. foreach ($colNumbers as $colNum) { diff --git a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php index 54960657dd3..f14961f6b6d 100644 --- a/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -248,7 +248,7 @@ public function listTableIndexes($table) $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); try { - $tableIndexes = $this->_conn->fetchAll($sql); + $tableIndexes = $this->_conn->fetchAllAssociative($sql); } catch (PDOException $e) { if ($e->getCode() === 'IMSSP') { return []; @@ -274,7 +274,7 @@ public function alterTable(TableDiff $tableDiff) if (count($tableDiff->removedColumns) > 0) { foreach ($tableDiff->removedColumns as $col) { $columnConstraintSql = $this->getColumnConstraintSQL($tableDiff->name, $col->getName()); - foreach ($this->_conn->fetchAll($columnConstraintSql) as $constraint) { + foreach ($this->_conn->fetchAllAssociative($columnConstraintSql) as $constraint) { $this->_conn->exec( sprintf( 'ALTER TABLE %s DROP CONSTRAINT %s', @@ -340,7 +340,7 @@ public function listTableDetails($tableName) : Table assert($platform instanceof SQLServerPlatform); $sql = $platform->getListTableMetadataSQL($tableName); - $tableOptions = $this->_conn->fetchAssoc($sql); + $tableOptions = $this->_conn->fetchAssociative($sql); if ($tableOptions !== false) { $table->addOption('comment', $tableOptions['table_comment']); diff --git a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php index 03076d96b6a..efdd5f9f4c8 100644 --- a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Types\StringType; use Doctrine\DBAL\Types\TextType; use Doctrine\DBAL\Types\Type; @@ -115,7 +114,7 @@ public function listTableForeignKeys($table, $database = null) } $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); - $tableForeignKeys = $this->_conn->fetchAll($sql); + $tableForeignKeys = $this->_conn->fetchAllAssociative($sql); if (! empty($tableForeignKeys)) { $createSql = $this->getCreateTableSQL($table); @@ -169,11 +168,10 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null $indexBuffer = []; // fetch primary - $stmt = $this->_conn->executeQuery(sprintf( + $indexArray = $this->_conn->fetchAllAssociative(sprintf( 'PRAGMA TABLE_INFO (%s)', $this->_conn->quote($tableName) )); - $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE); usort($indexArray, static function ($a, $b) { if ($a['pk'] === $b['pk']) { @@ -208,11 +206,10 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null $idx['primary'] = false; $idx['non_unique'] = ! $tableIndex['unique']; - $stmt = $this->_conn->executeQuery(sprintf( - 'PRAGMA INDEX_INFO (%s)', - $this->_conn->quote($keyName) - )); - $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE); + $indexArray = $this->_conn->fetchAllAssociative(sprintf( + 'PRAGMA INDEX_INFO (%s)', + $this->_conn->quote($keyName) + )); foreach ($indexArray as $indexColumnRow) { $idx['column_name'] = $indexColumnRow['name']; diff --git a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php b/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php index 2687c9d98ea..81a197ee117 100644 --- a/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php +++ b/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php @@ -87,7 +87,7 @@ public function queryAll($sql, array $params, array $types) foreach ($shards as $shard) { $this->conn->connect($shard['id']); - foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { + foreach ($this->conn->fetchAllAssociative($sql, $params, $types) as $row) { $result[] = $row; } } diff --git a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php index 62a6fd48447..a7d1ea5db17 100644 --- a/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php +++ b/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php @@ -159,7 +159,7 @@ public function getShards() INNER JOIN sys.federations f ON f.federation_id = d.federation_id WHERE f.name = ' . $this->conn->quote($this->federationName); - return $this->conn->fetchAll($sql); + return $this->conn->fetchAllAssociative($sql); } /** @@ -177,7 +177,7 @@ public function queryAll($sql, array $params = [], array $types = []) foreach ($shards as $shard) { $this->selectShard($shard['rangeLow']); - foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { + foreach ($this->conn->fetchAllAssociative($sql, $params, $types) as $row) { $result[] = $row; } } diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index cb6fbde7a71..1c593478254 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -2,12 +2,15 @@ namespace Doctrine\DBAL; +use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\Statement as DriverStatement; +use Doctrine\DBAL\ForwardCompatibility\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; use IteratorAggregate; use PDO; use Throwable; +use Traversable; use function is_array; use function is_string; @@ -15,7 +18,7 @@ * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support * for logging, DBAL mapping types, etc. */ -class Statement implements IteratorAggregate, DriverStatement +class Statement implements IteratorAggregate, DriverStatement, ForwardCompatibleResultStatement { /** * The SQL statement. @@ -219,6 +222,8 @@ public function errorInfo() /** * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { @@ -236,6 +241,8 @@ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) /** * Required by interface IteratorAggregate. * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + * * {@inheritdoc} */ public function getIterator() @@ -245,6 +252,8 @@ public function getIterator() /** * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { @@ -253,6 +262,8 @@ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEX /** * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { @@ -261,12 +272,176 @@ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = n /** * {@inheritDoc} + * + * @deprecated Use fetchOne() instead. */ public function fetchColumn($columnIndex = 0) { return $this->stmt->fetchColumn($columnIndex); } + /** + * {@inheritdoc} + * + * @throws DBALException + */ + public function fetchNumeric() + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + return $this->stmt->fetchNumeric(); + } + + return $this->stmt->fetch(FetchMode::NUMERIC); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritdoc} + * + * @throws DBALException + */ + public function fetchAssociative() + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + return $this->stmt->fetchAssociative(); + } + + return $this->stmt->fetch(FetchMode::ASSOCIATIVE); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritDoc} + * + * @throws DBALException + */ + public function fetchOne() + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + return $this->stmt->fetchOne(); + } + + return $this->stmt->fetch(FetchMode::COLUMN); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritdoc} + * + * @throws DBALException + */ + public function fetchAllNumeric() : array + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + return $this->stmt->fetchAllNumeric(); + } + + return $this->stmt->fetchAll(FetchMode::NUMERIC); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritdoc} + * + * @throws DBALException + */ + public function fetchAllAssociative() : array + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + return $this->stmt->fetchAllAssociative(); + } + + return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritDoc} + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateNumeric() : Traversable + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + while (($row = $this->stmt->fetchNumeric()) !== false) { + yield $row; + } + } else { + while (($row = $this->stmt->fetch(FetchMode::NUMERIC)) !== false) { + yield $row; + } + } + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritDoc} + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateAssociative() : Traversable + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + while (($row = $this->stmt->fetchAssociative()) !== false) { + yield $row; + } + } else { + while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { + yield $row; + } + } + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + + /** + * {@inheritDoc} + * + * @return Traversable + * + * @throws DBALException + */ + public function iterateColumn() : Traversable + { + try { + if ($this->stmt instanceof ForwardCompatibleResultStatement) { + while (($value = $this->stmt->fetchOne()) !== false) { + yield $value; + } + } else { + while (($value = $this->stmt->fetch(FetchMode::COLUMN)) !== false) { + yield $value; + } + } + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } + } + /** * Returns the number of rows affected by the last execution of this statement. * diff --git a/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php index 02b15cc1fc3..79c333dd89c 100644 --- a/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php +++ b/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php @@ -83,7 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (stripos($sql, 'select') === 0 || $input->getOption('force-fetch')) { - $resultSet = $conn->fetchAll($sql); + $resultSet = $conn->fetchAllAssociative($sql); } else { $resultSet = $conn->executeUpdate($sql); } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Connection.php b/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Connection.php new file mode 100644 index 00000000000..27c672bcb46 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Connection.php @@ -0,0 +1,37 @@ +connection = DriverManager::getConnection( + array_merge($this->connection->getParams(), [ + 'wrapperClass' => Connection::class, + ]), + $this->connection->getConfiguration(), + $this->connection->getEventManager() + ); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Statement.php b/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Statement.php new file mode 100644 index 00000000000..2fe0d98d95b --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Connection/BackwardCompatibility/Statement.php @@ -0,0 +1,158 @@ +stmt = $stmt; + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->bindParam($column, $variable, $type, $length); + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = ParameterType::STRING) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->bindValue($param, $value, $type); + } + + /** + * {@inheritdoc} + */ + public function closeCursor() + { + return $this->stmt->closeCursor(); + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->stmt->columnCount(); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorCode() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->errorCode(); + } + + /** + * {@inheritdoc} + * + * @deprecated The error information is available via exceptions. + */ + public function errorInfo() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->errorInfo(); + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->execute($params); + } + + /** + * {@inheritdoc} + * + * @deprecated Use one of the fetch- or iterate-related methods. + */ + public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) + { + return $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); + } + + /** + * {@inheritdoc} + * + * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. + */ + public function getIterator() + { + return new StatementIterator($this); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + */ + public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) + { + return $this->stmt->fetch($fetchMode); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. + */ + public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) + { + return $this->stmt->fetchAll($fetchMode, $fetchArgument); + } + + /** + * {@inheritdoc} + * + * @deprecated Use fetchOne() instead. + */ + public function fetchColumn($columnIndex = 0) + { + return $this->stmt->fetchColumn($columnIndex); + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + assert($this->stmt instanceof DriverStatement); + + return $this->stmt->rowCount(); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php b/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php new file mode 100644 index 00000000000..8d4c315670f --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Connection/FetchTest.php @@ -0,0 +1,114 @@ +query = TestUtil::generateResultSetQuery([ + [ + 'a' => 'foo', + 'b' => 1, + ], + [ + 'a' => 'bar', + 'b' => 2, + ], + [ + 'a' => 'baz', + 'b' => 3, + ], + ], $this->connection->getDatabasePlatform()); + } + + public function testFetchNumeric() : void + { + self::assertEquals(['foo', 1], $this->connection->fetchNumeric($this->query)); + } + + public function testFetchOne() : void + { + self::assertEquals('foo', $this->connection->fetchOne($this->query)); + } + + public function testFetchAssociative() : void + { + self::assertEquals([ + 'a' => 'foo', + 'b' => 1, + ], $this->connection->fetchAssociative($this->query)); + } + + public function testFetchAllNumeric() : void + { + self::assertEquals([ + ['foo', 1], + ['bar', 2], + ['baz', 3], + ], $this->connection->fetchAllNumeric($this->query)); + } + + public function testFetchAllAssociative() : void + { + self::assertEquals([ + [ + 'a' => 'foo', + 'b' => 1, + ], + [ + 'a' => 'bar', + 'b' => 2, + ], + [ + 'a' => 'baz', + 'b' => 3, + ], + ], $this->connection->fetchAllAssociative($this->query)); + } + + public function testIterateNumeric() : void + { + self::assertEquals([ + ['foo', 1], + ['bar', 2], + ['baz', 3], + ], iterator_to_array($this->connection->iterateNumeric($this->query))); + } + + public function testIterateAssociative() : void + { + self::assertEquals([ + [ + 'a' => 'foo', + 'b' => 1, + ], + [ + 'a' => 'bar', + 'b' => 2, + ], + [ + 'a' => 'baz', + 'b' => 3, + ], + ], iterator_to_array($this->connection->iterateAssociative($this->query))); + } + + public function testIterateColumn() : void + { + self::assertEquals([ + 'foo', + 'bar', + 'baz', + ], iterator_to_array($this->connection->iterateColumn($this->query))); + } +} diff --git a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php index 53f9a41cbda..86fe190c790 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php @@ -30,7 +30,7 @@ protected function setUp() : void $platform = $this->createMock(DB2Platform::class); $this->conn = $this ->getMockBuilder(Connection::class) - ->onlyMethods(['fetchAll', 'quote']) + ->onlyMethods(['fetchAllAssociative', 'quote']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); $this->manager = new DB2SchemaManager($this->conn); @@ -44,7 +44,7 @@ protected function setUp() : void public function testListTableNamesFiltersAssetNamesCorrectly() : void { $this->conn->getConfiguration()->setFilterSchemaAssetsExpression('/^(?!T_)/'); - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ + $this->conn->expects($this->once())->method('fetchAllAssociative')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], @@ -67,7 +67,7 @@ public function testAssetFilteringSetsACallable() : void { $filterExpression = '/^(?!T_)/'; $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ + $this->conn->expects($this->once())->method('fetchAllAssociative')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], @@ -96,7 +96,7 @@ public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() : voi return in_array($assetName, $accepted); }); $this->conn->expects($this->any())->method('quote'); - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ + $this->conn->expects($this->once())->method('fetchAllAssociative')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], @@ -121,7 +121,7 @@ public function testSettingNullExpressionWillResetCallable() : void return in_array($assetName, $accepted); }); $this->conn->expects($this->any())->method('quote'); - $this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([ + $this->conn->expects($this->atLeastOnce())->method('fetchAllAssociative')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], @@ -156,7 +156,7 @@ 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->exactly(2))->method('fetchAllAssociative')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], diff --git a/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php index 934b3e97bef..3cd1f928d0b 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php @@ -23,11 +23,15 @@ class MySqlSchemaManagerTest extends TestCase protected function setUp() : void { - $eventManager = new EventManager(); - $driverMock = $this->createMock(Driver::class); - $platform = $this->createMock(MySqlPlatform::class); + $eventManager = new EventManager(); + $driverMock = $this->createMock(Driver::class); + + $platform = $this->createMock(MySqlPlatform::class); + $platform->method('getListTableForeignKeysSQL') + ->willReturn(''); + $this->conn = $this->getMockBuilder(Connection::class) - ->onlyMethods(['fetchAll']) + ->onlyMethods(['fetchAllAssociative']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); $this->manager = new MySqlSchemaManager($this->conn); @@ -35,7 +39,7 @@ protected function setUp() : void public function testCompositeForeignKeys() : void { - $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue($this->getFKDefinition())); + $this->conn->expects($this->once())->method('fetchAllAssociative')->will($this->returnValue($this->getFKDefinition())); $fkeys = $this->manager->listTableForeignKeys('dummy'); self::assertCount(1, $fkeys, 'Table has to have one foreign key.'); diff --git a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php index eafbd69cfcb..2143bb2be7f 100644 --- a/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php @@ -16,7 +16,7 @@ class PoolingShardManagerTest extends TestCase private function createConnectionMock() : PoolingShardConnection { return $this->getMockBuilder(PoolingShardConnection::class) - ->onlyMethods(['connect', 'getParams', 'fetchAll']) + ->onlyMethods(['connect', 'getParams', 'fetchAllAssociative']) ->disableOriginalConstructor() ->getMock(); } @@ -101,12 +101,12 @@ public function testQueryAll() : void )); $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); $conn->expects($this->at(3)) - ->method('fetchAll') + ->method('fetchAllAssociative') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 1] ])); $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); $conn->expects($this->at(5)) - ->method('fetchAll') + ->method('fetchAllAssociative') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 2] ])); @@ -131,12 +131,12 @@ public function testQueryAllWithStaticShardChoser() : void )); $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); $conn->expects($this->at(3)) - ->method('fetchAll') + ->method('fetchAllAssociative') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 1] ])); $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); $conn->expects($this->at(5)) - ->method('fetchAll') + ->method('fetchAllAssociative') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 2] ])); diff --git a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php index 202748be6d8..2f67996acdf 100644 --- a/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php +++ b/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php @@ -30,7 +30,7 @@ protected function setUp() : void $this->commandTester = new CommandTester($this->command); $this->connectionMock = $this->createMock(Connection::class); - $this->connectionMock->method('fetchAll') + $this->connectionMock->method('fetchAllAssociative') ->willReturn([[1]]); $this->connectionMock->method('executeUpdate') ->willReturn(42); @@ -68,7 +68,7 @@ public function testIncorrectDepthOption() : void public function testSelectStatementsPrintsResult() : void { - $this->expectConnectionFetchAll(); + $this->expectConnectionFetchAllAssociative(); $exitCode = $this->commandTester->execute([ 'command' => $this->command->getName(), @@ -100,22 +100,22 @@ private function expectConnectionExecuteUpdate() : void ->method('executeUpdate'); $this->connectionMock ->expects($this->exactly(0)) - ->method('fetchAll'); + ->method('fetchAllAssociative'); } - private function expectConnectionFetchAll() : void + private function expectConnectionFetchAllAssociative() : void { $this->connectionMock ->expects($this->exactly(0)) ->method('executeUpdate'); $this->connectionMock ->expects($this->exactly(1)) - ->method('fetchAll'); + ->method('fetchAllAssociative'); } public function testStatementsWithFetchResultPrintsResult() : void { - $this->expectConnectionFetchAll(); + $this->expectConnectionFetchAllAssociative(); $this->commandTester->execute([ 'command' => $this->command->getName(), diff --git a/tests/Doctrine/Tests/TestUtil.php b/tests/Doctrine/Tests/TestUtil.php index b5f4dd010c2..ad070abf491 100644 --- a/tests/Doctrine/Tests/TestUtil.php +++ b/tests/Doctrine/Tests/TestUtil.php @@ -4,9 +4,15 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Platforms\AbstractPlatform; use PHPUnit\Framework\Assert; +use function array_keys; +use function array_map; +use function array_values; use function explode; use function extension_loaded; +use function implode; +use function is_string; use function unlink; /** @@ -207,4 +213,24 @@ public static function getTempConnection() : Connection { return DriverManager::getConnection(self::getParamsForTemporaryConnection()); } + + /** + * Generates a query that will return the given rows without the need to create a temporary table. + * + * @param array> $rows + */ + public static function generateResultSetQuery(array $rows, AbstractPlatform $platform) : string + { + return implode(' UNION ALL ', array_map(static function (array $row) use ($platform) : string { + return $platform->getDummySelectSQL( + implode(', ', array_map(static function (string $column, $value) use ($platform) : string { + if (is_string($value)) { + $value = $platform->quoteStringLiteral($value); + } + + return $value . ' ' . $platform->quoteIdentifier($column); + }, array_keys($row), array_values($row))) + ); + }, $rows)); + } } From 639b2f2b0dd110c549d7aeac5cc37f6c36f1e6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 25 May 2020 21:49:07 +0200 Subject: [PATCH 3/9] Allow php 8 --- composer.json | 2 +- composer.lock | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 432fee59dab..afa8fb12228 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ {"name": "Jonathan Wage", "email": "jonwage@gmail.com"} ], "require": { - "php": "^7.3", + "php": "^7.3 || ^8.0", "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ocramius/package-versions": "^1.4" diff --git a/composer.lock b/composer.lock index 6aeb09d62e8..dd074f6e5a2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "893d32dea2abc8c66017ee58e435fac8", + "content-hash": "375d7b1967e204d71959234a23055326", "packages": [ { "name": "doctrine/cache", @@ -1816,6 +1816,16 @@ "testing", "xunit" ], + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-03T14:40:04+00:00" }, { @@ -1909,6 +1919,12 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-03-30T11:59:20+00:00" }, { @@ -2127,6 +2143,12 @@ "environment", "hhvm" ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-03-31T12:14:15+00:00" }, { @@ -3250,7 +3272,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3" + "php": "^7.3 || ^8.0" }, "platform-dev": [], "platform-overrides": { From 8f331e81e237790311697b4511388521b19e0e97 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 5 Apr 2019 14:45:12 -0700 Subject: [PATCH 4/9] Removed errorCode() and errorInfo() methods from Connection and Statement APIs --- UPGRADE.md | 4 +++ phpstan.neon.dist | 1 - src/Connection.php | 22 ------------ src/Driver/Connection.php | 18 ---------- src/Driver/IBMDB2/DB2Connection.php | 24 ------------- src/Driver/IBMDB2/DB2Statement.php | 24 ------------- src/Driver/Mysqli/MysqliConnection.php | 20 ----------- src/Driver/Mysqli/MysqliStatement.php | 18 ---------- src/Driver/OCI8/OCI8Connection.php | 35 ++----------------- src/Driver/OCI8/OCI8Statement.php | 33 +---------------- src/Driver/PDOConnection.php | 16 --------- src/Driver/PDOStatement.php | 16 --------- .../SQLAnywhere/SQLAnywhereConnection.php | 22 ------------ .../SQLAnywhere/SQLAnywhereStatement.php | 22 ------------ src/Driver/SQLSrv/SQLSrvConnection.php | 27 -------------- src/Driver/SQLSrv/SQLSrvStatement.php | 27 -------------- src/Driver/Statement.php | 20 ----------- src/Portability/Statement.php | 24 ------------- src/Statement.php | 22 ------------ tests/Driver/OCI8/OCI8StatementTest.php | 12 ++----- tests/Portability/StatementTest.php | 22 ------------ 21 files changed, 9 insertions(+), 420 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 8717e37dd0c..55824bdb046 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `::errorCode()` and `::errorInfo()` removed from `Connection` and `Statement` APIs + +The error information is available in `DriverException` thrown in case of an error. + ## BC BREAK: Dropped support for `FetchMode::CUSTOM_OBJECT` and `::STANDARD_OBJECT` Instead of fetching an object, fetch an array and map it to an object of the desired class. diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 056d90e56df..35fa53a5910 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -27,7 +27,6 @@ parameters: - '~^Method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint::onEvent\(\) should return string\|null but returns false\.\z~' - '~^Method Doctrine\\DBAL\\Schema\\(Oracle|PostgreSql|SQLServer)SchemaManager::_getPortableTableDefinition\(\) should return array but returns string\.\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~' # https://bugs.php.net/bug.php?id=78126 - '~^Call to an undefined method PDO::sqliteCreateFunction\(\)\.\z~' diff --git a/src/Connection.php b/src/Connection.php index 01bc249005a..26706d25802 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -1320,28 +1320,6 @@ public function getTransactionNestingLevel() return $this->transactionNestingLevel; } - /** - * Fetches the SQLSTATE associated with the last database operation. - * - * @deprecated The error information is available via exceptions. - * - * @return string|null The last error code. - */ - public function errorCode() - { - return $this->getWrappedConnection()->errorCode(); - } - - /** - * {@inheritDoc} - * - * @deprecated The error information is available via exceptions. - */ - 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. diff --git a/src/Driver/Connection.php b/src/Driver/Connection.php index d8e68b81490..7817f60adad 100644 --- a/src/Driver/Connection.php +++ b/src/Driver/Connection.php @@ -71,22 +71,4 @@ public function commit(); * @return bool TRUE on success or FALSE on failure. */ public function rollBack(); - - /** - * Returns the error code associated with the last operation on the database handle. - * - * @deprecated The error information is available via exceptions. - * - * @return string|null The error code, or null if no operation has been run on the database handle. - */ - public function errorCode(); - - /** - * Returns extended error information associated with the last operation on the database handle. - * - * @deprecated The error information is available via exceptions. - * - * @return mixed[] - */ - public function errorInfo(); } diff --git a/src/Driver/IBMDB2/DB2Connection.php b/src/Driver/IBMDB2/DB2Connection.php index e8905f11a38..bfea7420566 100644 --- a/src/Driver/IBMDB2/DB2Connection.php +++ b/src/Driver/IBMDB2/DB2Connection.php @@ -10,7 +10,6 @@ use function assert; use function db2_autocommit; use function db2_commit; -use function db2_conn_error; use function db2_conn_errormsg; use function db2_connect; use function db2_escape_string; @@ -166,27 +165,4 @@ public function rollBack() return $result; } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - return db2_conn_error($this->conn); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return [ - 0 => db2_conn_errormsg($this->conn), - 1 => $this->errorCode(), - ]; - } } diff --git a/src/Driver/IBMDB2/DB2Statement.php b/src/Driver/IBMDB2/DB2Statement.php index 0f42dac26b6..d485f8ed576 100644 --- a/src/Driver/IBMDB2/DB2Statement.php +++ b/src/Driver/IBMDB2/DB2Statement.php @@ -16,7 +16,6 @@ use function db2_free_result; use function db2_num_fields; use function db2_num_rows; -use function db2_stmt_error; use function db2_stmt_errormsg; use function error_get_last; use function fclose; @@ -154,29 +153,6 @@ public function columnCount() return 0; } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - return db2_stmt_error(); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return [ - db2_stmt_errormsg(), - db2_stmt_error(), - ]; - } - /** * {@inheritdoc} */ diff --git a/src/Driver/Mysqli/MysqliConnection.php b/src/Driver/Mysqli/MysqliConnection.php index ba1c7fbbfe9..93274207eec 100644 --- a/src/Driver/Mysqli/MysqliConnection.php +++ b/src/Driver/Mysqli/MysqliConnection.php @@ -193,26 +193,6 @@ public function rollBack() return $this->conn->rollback(); } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - return $this->conn->errno; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return $this->conn->error; - } - /** * Apply the driver options to the connection. * diff --git a/src/Driver/Mysqli/MysqliStatement.php b/src/Driver/Mysqli/MysqliStatement.php index ac9f03abbf8..f9e71042af0 100644 --- a/src/Driver/Mysqli/MysqliStatement.php +++ b/src/Driver/Mysqli/MysqliStatement.php @@ -463,24 +463,6 @@ public function fetchAllAssociative() : array return FetchUtils::fetchAllAssociative($this); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->_stmt->errno; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return $this->_stmt->error; - } - /** * {@inheritdoc} */ diff --git a/src/Driver/OCI8/OCI8Connection.php b/src/Driver/OCI8/OCI8Connection.php index 378094383e5..efdb3b4d9a8 100644 --- a/src/Driver/OCI8/OCI8Connection.php +++ b/src/Driver/OCI8/OCI8Connection.php @@ -181,7 +181,7 @@ public function beginTransaction() public function commit() { if (! oci_commit($this->dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; @@ -195,42 +195,11 @@ public function commit() public function rollBack() { if (! oci_rollback($this->dbh)) { - throw OCI8Exception::fromErrorInfo($this->errorInfo()); + throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; return true; } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - $error = oci_error($this->dbh); - if ($error !== false) { - $error = $error['code']; - } - - return $error; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - $error = oci_error($this->dbh); - - if ($error === false) { - return []; - } - - return $error; - } } diff --git a/src/Driver/OCI8/OCI8Statement.php b/src/Driver/OCI8/OCI8Statement.php index 229e348f45c..9e29b49ad16 100644 --- a/src/Driver/OCI8/OCI8Statement.php +++ b/src/Driver/OCI8/OCI8Statement.php @@ -356,37 +356,6 @@ public function columnCount() return 0; } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - $error = oci_error($this->_sth); - if ($error !== false) { - $error = $error['code']; - } - - return $error; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - $error = oci_error($this->_sth); - - if ($error === false) { - return []; - } - - return $error; - } - /** * {@inheritdoc} */ @@ -405,7 +374,7 @@ public function execute($params = null) $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; diff --git a/src/Driver/PDOConnection.php b/src/Driver/PDOConnection.php index 7cceff36ef2..77938099311 100644 --- a/src/Driver/PDOConnection.php +++ b/src/Driver/PDOConnection.php @@ -138,22 +138,6 @@ public function rollBack() return $this->connection->rollBack(); } - /** - * {@inheritDoc} - */ - public function errorCode() - { - return $this->connection->errorCode(); - } - - /** - * {@inheritDoc} - */ - public function errorInfo() - { - return $this->connection->errorInfo(); - } - public function getWrappedConnection() : PDO { return $this->connection; diff --git a/src/Driver/PDOStatement.php b/src/Driver/PDOStatement.php index be6c41a3e12..6e176caa628 100644 --- a/src/Driver/PDOStatement.php +++ b/src/Driver/PDOStatement.php @@ -115,22 +115,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * {@inheritdoc} - */ - public function errorCode() - { - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ diff --git a/src/Driver/SQLAnywhere/SQLAnywhereConnection.php b/src/Driver/SQLAnywhere/SQLAnywhereConnection.php index 285d7b84ded..d07711658e9 100644 --- a/src/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/src/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -15,8 +15,6 @@ use function sasql_affected_rows; use function sasql_commit; use function sasql_connect; -use function sasql_error; -use function sasql_errorcode; use function sasql_escape_string; use function sasql_insert_id; use function sasql_pconnect; @@ -89,26 +87,6 @@ public function commit() return true; } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - return sasql_errorcode($this->connection); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return sasql_error($this->connection); - } - public function exec(string $statement) : int { if (sasql_real_query($this->connection, $statement) === false) { diff --git a/src/Driver/SQLAnywhere/SQLAnywhereStatement.php b/src/Driver/SQLAnywhere/SQLAnywhereStatement.php index e5c1928610a..4c9d86fa77d 100644 --- a/src/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/src/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -20,8 +20,6 @@ use function sasql_prepare; use function sasql_stmt_affected_rows; use function sasql_stmt_bind_param_ex; -use function sasql_stmt_errno; -use function sasql_stmt_error; use function sasql_stmt_execute; use function sasql_stmt_field_count; use function sasql_stmt_reset; @@ -138,26 +136,6 @@ public function columnCount() return sasql_stmt_field_count($this->stmt); } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - return sasql_stmt_errno($this->stmt); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return sasql_stmt_error($this->stmt); - } - /** * {@inheritdoc} * diff --git a/src/Driver/SQLSrv/SQLSrvConnection.php b/src/Driver/SQLSrv/SQLSrvConnection.php index 79158cf6822..a97f26961ff 100644 --- a/src/Driver/SQLSrv/SQLSrvConnection.php +++ b/src/Driver/SQLSrv/SQLSrvConnection.php @@ -14,13 +14,11 @@ use function sqlsrv_commit; use function sqlsrv_configure; use function sqlsrv_connect; -use function sqlsrv_errors; use function sqlsrv_query; use function sqlsrv_rollback; use function sqlsrv_rows_affected; use function sqlsrv_server_info; use function str_replace; -use const SQLSRV_ERR_ERRORS; /** * SQL Server implementation for the Connection interface. @@ -173,29 +171,4 @@ public function rollBack() return true; } - - /** - * {@inheritDoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors !== null) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritDoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } } diff --git a/src/Driver/SQLSrv/SQLSrvStatement.php b/src/Driver/SQLSrv/SQLSrvStatement.php index d13a48b52d0..afa6d923731 100644 --- a/src/Driver/SQLSrv/SQLSrvStatement.php +++ b/src/Driver/SQLSrv/SQLSrvStatement.php @@ -12,7 +12,6 @@ use function array_key_exists; use function is_int; use function is_numeric; -use function sqlsrv_errors; use function sqlsrv_execute; use function sqlsrv_fetch; use function sqlsrv_fetch_array; @@ -26,7 +25,6 @@ use function SQLSRV_SQLTYPE_VARBINARY; use function stripos; use const SQLSRV_ENC_BINARY; -use const SQLSRV_ERR_ERRORS; use const SQLSRV_FETCH_ASSOC; use const SQLSRV_FETCH_BOTH; use const SQLSRV_FETCH_NUMERIC; @@ -203,31 +201,6 @@ public function columnCount() return 0; } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); - if ($errors !== null) { - return $errors[0]['code']; - } - - return false; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); - } - /** * {@inheritdoc} */ diff --git a/src/Driver/Statement.php b/src/Driver/Statement.php index e6f0135fcae..6599d822a65 100644 --- a/src/Driver/Statement.php +++ b/src/Driver/Statement.php @@ -57,26 +57,6 @@ public function bindValue($param, $value, $type = ParameterType::STRING); */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null); - /** - * Fetches the SQLSTATE associated with the last operation on the statement handle. - * - * @deprecated The error information is available via exceptions. - * - * @see Doctrine_Adapter_Interface::errorCode() - * - * @return string|int|bool The error code string. - */ - public function errorCode(); - - /** - * Fetches extended error information associated with the last operation on the statement handle. - * - * @deprecated The error information is available via exceptions. - * - * @return mixed[] The error info array. - */ - public function errorInfo(); - /** * Executes a prepared statement * diff --git a/src/Portability/Statement.php b/src/Portability/Statement.php index 3465e8077c6..1d1a85887c3 100644 --- a/src/Portability/Statement.php +++ b/src/Portability/Statement.php @@ -79,30 +79,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} */ diff --git a/src/Statement.php b/src/Statement.php index 37d91027c72..def50288964 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -196,28 +196,6 @@ public function columnCount() return $this->stmt->columnCount(); } - /** - * Fetches the SQLSTATE associated with the last operation on the statement. - * - * @deprecated The error information is available via exceptions. - * - * @return string|int|bool - */ - public function errorCode() - { - return $this->stmt->errorCode(); - } - - /** - * {@inheritDoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - return $this->stmt->errorInfo(); - } - /** * {@inheritdoc} * diff --git a/tests/Driver/OCI8/OCI8StatementTest.php b/tests/Driver/OCI8/OCI8StatementTest.php index 6a4ff3db823..068be3c1a05 100644 --- a/tests/Driver/OCI8/OCI8StatementTest.php +++ b/tests/Driver/OCI8/OCI8StatementTest.php @@ -36,7 +36,7 @@ protected function setUp() : void public function testExecute(array $params) : void { $statement = $this->getMockBuilder(OCI8Statement::class) - ->onlyMethods(['bindValue', 'errorInfo']) + ->onlyMethods(['bindValue']) ->disableOriginalConstructor() ->getMock(); @@ -59,17 +59,9 @@ public function testExecute(array $params) : void self::equalTo($params[2]) ); - // the return value is irrelevant to the test - // but it has to be compatible with the method signature - $statement->method('errorInfo') - ->willReturn(false); - // 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) - ->onlyMethods(['getExecuteMode']) - ->disableOriginalConstructor() - ->getMock(); + $conn = $this->createMock(OCI8Connection::class); $conn->expects(self::once()) ->method('getExecuteMode'); diff --git a/tests/Portability/StatementTest.php b/tests/Portability/StatementTest.php index 91ceabc406f..49362e21ee7 100644 --- a/tests/Portability/StatementTest.php +++ b/tests/Portability/StatementTest.php @@ -80,28 +80,6 @@ public function testColumnCount() : void self::assertSame($columnCount, $this->stmt->columnCount()); } - public function testErrorCode() : void - { - $errorCode = '666'; - - $this->wrappedStmt->expects(self::once()) - ->method('errorCode') - ->will(self::returnValue($errorCode)); - - self::assertSame($errorCode, $this->stmt->errorCode()); - } - - public function testErrorInfo() : void - { - $errorInfo = ['666', 'Evil error.']; - - $this->wrappedStmt->expects(self::once()) - ->method('errorInfo') - ->will(self::returnValue($errorInfo)); - - self::assertSame($errorInfo, $this->stmt->errorInfo()); - } - public function testExecute() : void { $params = [ From bfa733d8844312412b9327dc135b771842003988 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 15 Jan 2020 20:48:45 -0800 Subject: [PATCH 5/9] Removed Connection::project() The methods has more limitations and caveats than provides real use: 1. It fetches all data in memory which is often inefficient (see #2718). 2. It fetches rows in memory one by one instead of using `fetchAll()`. 4. It doesn't allow to specify the statement fetch mode since it's instantiated internally. 5. It can be easily replaced with: ```php foreach ($conn->executeQuery($query, $params, $types) as $value) { yield $function($value); } ``` --- UPGRADE.md | 4 ++++ src/Connection.php | 28 ---------------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 55824bdb046..513fa074e85 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement::project()` has been removed + +- The `Statement::project()` method has been removed. Use `::executeQuery()` and fetch the data from the statement using one of the `Statement::fetch*()` methods instead. + ## BC BREAK `::errorCode()` and `::errorInfo()` removed from `Connection` and `Statement` APIs The error information is available in `DriverException` thrown in case of an error. diff --git a/src/Connection.php b/src/Connection.php index 26706d25802..9b8a4b62c6f 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -1187,34 +1187,6 @@ public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qc return $stmt; } - /** - * Executes an, optionally parametrized, SQL query and returns the result, - * applying a given projection/transformation function on each row of the result. - * - * @deprecated - * - * @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. - * - * @return mixed[] The projected result of the query. - */ - public function project($query, array $params, Closure $function) - { - $result = []; - $stmt = $this->executeQuery($query, $params); - - while ($row = $stmt->fetch()) { - $result[] = $function($row); - } - - $stmt->closeCursor(); - - return $result; - } - public function query(string $sql) : ResultStatement { $connection = $this->getWrappedConnection(); From a48cad1e5f6b9a49a102d91ff4af3ee7e6ab090c Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Fri, 3 Jan 2020 00:48:44 -0800 Subject: [PATCH 6/9] Dropped handling of one-based numeric arrays of parameters in Statement::execute() --- UPGRADE.md | 4 ++ src/Driver/OCI8/OCI8Statement.php | 4 +- src/Driver/SQLSrv/SQLSrvStatement.php | 4 +- src/Driver/Statement.php | 2 +- tests/Driver/OCI8/OCI8StatementTest.php | 72 ------------------------- 5 files changed, 7 insertions(+), 79 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 513fa074e85..4a81d1a32b7 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK: Dropped handling of one-based numeric arrays of parameters in `Statement::execute()` + +The statement implementations no longer detect whether `$params` is a zero- or one-based array. A zero-based numeric array is expected. + ## BC BREAK `Statement::project()` has been removed - The `Statement::project()` method has been removed. Use `::executeQuery()` and fetch the data from the statement using one of the `Statement::fetch*()` methods instead. diff --git a/src/Driver/OCI8/OCI8Statement.php b/src/Driver/OCI8/OCI8Statement.php index 9e29b49ad16..2383dd307ed 100644 --- a/src/Driver/OCI8/OCI8Statement.php +++ b/src/Driver/OCI8/OCI8Statement.php @@ -10,7 +10,6 @@ use Doctrine\DBAL\ParameterType; use InvalidArgumentException; use IteratorAggregate; -use function array_key_exists; use function assert; use function count; use function implode; @@ -362,9 +361,8 @@ public function columnCount() public function execute($params = null) { if ($params !== null) { - $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { - if ($hasZeroIndex && is_int($key)) { + if (is_int($key)) { $this->bindValue($key + 1, $val); } else { $this->bindValue($key, $val); diff --git a/src/Driver/SQLSrv/SQLSrvStatement.php b/src/Driver/SQLSrv/SQLSrvStatement.php index afa6d923731..00a69bae3fe 100644 --- a/src/Driver/SQLSrv/SQLSrvStatement.php +++ b/src/Driver/SQLSrv/SQLSrvStatement.php @@ -9,7 +9,6 @@ use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use IteratorAggregate; -use function array_key_exists; use function is_int; use function is_numeric; use function sqlsrv_execute; @@ -207,9 +206,8 @@ public function columnCount() public function execute($params = null) { if ($params !== null) { - $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { - if ($hasZeroIndex && is_int($key)) { + if (is_int($key)) { $this->bindValue($key + 1, $val); } else { $this->bindValue($key, $val); diff --git a/src/Driver/Statement.php b/src/Driver/Statement.php index 6599d822a65..4fb7865e28f 100644 --- a/src/Driver/Statement.php +++ b/src/Driver/Statement.php @@ -66,7 +66,7 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l * if any, of their associated parameter markers or pass an array of input-only * parameter values. * - * @param mixed[]|null $params An array of values with as many elements as there are + * @param mixed[]|null $params A numeric array of values with as many elements as there are * bound parameters in the SQL statement being executed. * * @return bool TRUE on success or FALSE on failure. diff --git a/tests/Driver/OCI8/OCI8StatementTest.php b/tests/Driver/OCI8/OCI8StatementTest.php index 068be3c1a05..1de85da0b09 100644 --- a/tests/Driver/OCI8/OCI8StatementTest.php +++ b/tests/Driver/OCI8/OCI8StatementTest.php @@ -2,11 +2,9 @@ namespace Doctrine\DBAL\Tests\Driver\OCI8; -use Doctrine\DBAL\Driver\OCI8\OCI8Connection; use Doctrine\DBAL\Driver\OCI8\OCI8Exception; use Doctrine\DBAL\Driver\OCI8\OCI8Statement; use PHPUnit\Framework\TestCase; -use ReflectionProperty; use function extension_loaded; class OCI8StatementTest extends TestCase @@ -20,76 +18,6 @@ protected function setUp() : void parent::setUp(); } - /** - * This scenario shows that when the first parameter is not null - * it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1. - * - * This also verifies that the statement will check with the connection to - * see what the current execution mode is. - * - * The expected exception is due to oci_execute failing due to no valid connection. - * - * @param mixed[] $params - * - * @dataProvider executeDataProvider - */ - public function testExecute(array $params) : void - { - $statement = $this->getMockBuilder(OCI8Statement::class) - ->onlyMethods(['bindValue']) - ->disableOriginalConstructor() - ->getMock(); - - $statement->expects(self::at(0)) - ->method('bindValue') - ->with( - self::equalTo(1), - self::equalTo($params[0]) - ); - $statement->expects(self::at(1)) - ->method('bindValue') - ->with( - self::equalTo(2), - self::equalTo($params[1]) - ); - $statement->expects(self::at(2)) - ->method('bindValue') - ->with( - self::equalTo(3), - self::equalTo($params[2]) - ); - - // 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->createMock(OCI8Connection::class); - $conn->expects(self::once()) - ->method('getExecuteMode'); - - $reflProperty = new ReflectionProperty($statement, '_conn'); - $reflProperty->setAccessible(true); - $reflProperty->setValue($statement, $conn); - - $this->expectException(OCI8Exception::class); - $statement->execute($params); - } - - /** - * @return array> - */ - public static function executeDataProvider() : iterable - { - return [ - // $hasZeroIndex = isset($params[0]); == true - [ - [0 => 'test', 1 => null, 2 => 'value'], - ], - // $hasZeroIndex = isset($params[0]); == false - [ - [0 => null, 1 => 'test', 2 => 'value'], - ], - ]; - } - /** * @dataProvider nonTerminatedLiteralProvider */ From 96f8cabf4fed81d00dd7a1b1cde3c76f9e2f8a5f Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Sat, 9 May 2020 15:09:30 -0700 Subject: [PATCH 7/9] Replace the concept of the statement fetch modes with an explicit API --- UPGRADE.md | 10 + docs/en/reference/caching.rst | 2 +- .../data-retrieval-and-manipulation.rst | 34 ++-- src/Cache/ArrayStatement.php | 112 ++--------- src/Cache/ResultCacheStatement.php | 177 ++--------------- src/Connection.php | 181 +++--------------- src/Connections/MasterSlaveConnection.php | 2 - src/Driver/AbstractMySQLDriver.php | 2 +- src/Driver/AbstractPostgreSQLDriver.php | 2 +- src/Driver/AbstractSQLAnywhereDriver.php | 2 +- src/Driver/AbstractSQLServerDriver.php | 2 +- src/Driver/FetchUtils.php | 18 +- src/Driver/IBMDB2/DB2Statement.php | 102 +++------- src/Driver/Mysqli/MysqliStatement.php | 130 +------------ src/Driver/OCI8/OCI8Connection.php | 4 +- src/Driver/OCI8/OCI8Statement.php | 160 ++-------------- src/Driver/PDOSqlsrv/Connection.php | 7 +- src/Driver/PDOStatement.php | 136 ++++--------- src/Driver/ResultStatement.php | 68 ++++--- .../SQLAnywhere/SQLAnywhereConnection.php | 18 +- .../SQLAnywhere/SQLAnywhereStatement.php | 112 +---------- src/Driver/SQLSrv/SQLSrvConnection.php | 7 +- src/Driver/SQLSrv/SQLSrvStatement.php | 131 ++----------- src/Driver/StatementIterator.php | 29 --- src/FetchMode.php | 54 ------ .../Driver/ResultStatement.php | 47 +---- src/ForwardCompatibility/ResultStatement.php | 30 +-- src/Portability/Connection.php | 22 +-- src/Portability/Statement.php | 150 +++------------ src/ResultStatement.php | 41 ++++ src/Schema/AbstractSchemaManager.php | 4 +- src/Schema/PostgreSqlSchemaManager.php | 11 +- src/Schema/SqliteSchemaManager.php | 2 +- src/Statement.php | 130 +++---------- tests/ConnectionTest.php | 27 ++- tests/Driver/AbstractMySQLDriverTest.php | 2 +- tests/Driver/AbstractPostgreSQLDriverTest.php | 2 +- tests/Driver/StatementIteratorTest.php | 106 ---------- tests/Functional/BlobTest.php | 3 +- .../BackwardCompatibility/Connection.php | 33 ---- .../BackwardCompatibility/FetchTest.php | 23 --- .../BackwardCompatibility/Statement.php | 154 --------------- tests/Functional/ConnectionTest.php | 2 +- tests/Functional/DataAccessTest.php | 165 +++++----------- .../Functional/Driver/OCI8/StatementTest.php | 4 +- .../Functional/Driver/PDOPgSql/DriverTest.php | 2 +- .../Driver/PDOPgsqlConnectionTest.php | 3 +- .../Driver/PDOSqlsrv/DriverTest.php | 2 +- .../Functional/LikeWildcardsEscapingTest.php | 2 +- .../Functional/MasterSlaveConnectionTest.php | 12 +- tests/Functional/ModifyLimitQueryTest.php | 2 +- tests/Functional/NamedParametersTest.php | 3 +- .../Platform/DateExpressionTest.php | 2 +- .../Platform/DefaultExpressionTest.php | 3 +- tests/Functional/Platform/QuotingTest.php | 2 +- tests/Functional/PortabilityTest.php | 36 ++-- tests/Functional/ResultCacheTest.php | 120 +++++++----- tests/Functional/Schema/DefaultValueTest.php | 2 +- .../Schema/MySqlSchemaManagerTest.php | 2 +- .../SchemaManagerFunctionalTestCase.php | 4 +- .../Schema/SqliteSchemaManagerTest.php | 2 +- tests/Functional/StatementTest.php | 45 +++-- tests/Functional/TemporaryTableTest.php | 4 +- tests/Functional/Ticket/DBAL202Test.php | 4 +- tests/Functional/Ticket/DBAL421Test.php | 2 +- tests/Functional/Ticket/DBAL630Test.php | 10 +- tests/Functional/TypeConversionTest.php | 2 +- tests/Functional/Types/BinaryTest.php | 2 +- tests/Functional/WriteTest.php | 20 +- tests/Portability/StatementTest.php | 10 - 70 files changed, 593 insertions(+), 2165 deletions(-) delete mode 100644 src/Driver/StatementIterator.php delete mode 100644 src/FetchMode.php create mode 100644 src/ResultStatement.php delete mode 100644 tests/Driver/StatementIteratorTest.php delete mode 100644 tests/Functional/Connection/BackwardCompatibility/Connection.php delete mode 100644 tests/Functional/Connection/BackwardCompatibility/FetchTest.php delete mode 100644 tests/Functional/Connection/BackwardCompatibility/Statement.php diff --git a/UPGRADE.md b/UPGRADE.md index 4a81d1a32b7..970d8b9a110 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,15 @@ # Upgrade to 3.0 +## Removed `FetchMode` and the corresponding methods + +1. The `FetchMode` class and the `setFetchMode()` method of the `Connection` and `Statement` interfaces are removed. +2. The `Statement::fetch()` method is replaced with `fetchNumeric()`, `fetchAssociative()` and `fetchOne()`. +3. The `Statement::fetchAll()` method is replaced with `fetchAllNumeric()`, `fetchAllAssociative()` and `fechColumn()`. +4. The `Statement::fetchColumn()` method is replaced with `fetchOne()`. +5. The `Connection::fetchArray()` and `fetchAssoc()` methods are replaced with `fetchNumeric()` and `fetchAssociative()` respectively. +6. The `StatementIterator` class is removed. The usage of a `Statement` object as `Traversable` is no longer possible. Use `iterateNumeric()`, `iterateAssociative()` and `iterateColumn()` instead. +7. Fetching data in mixed mode (former `FetchMode::MIXED`) is no longer possible. + ## BC BREAK: Dropped handling of one-based numeric arrays of parameters in `Statement::execute()` The statement implementations no longer detect whether `$params` is a zero- or one-based array. A zero-based numeric array is expected. diff --git a/docs/en/reference/caching.rst b/docs/en/reference/caching.rst index faf6f16b870..735e44329f3 100644 --- a/docs/en/reference/caching.rst +++ b/docs/en/reference/caching.rst @@ -42,7 +42,7 @@ object is closed: executeCacheQuery($query, $params, $types, new QueryCacheProfile(0, "some key")); - $data = $stmt->fetchAll(); + $data = $stmt->fetchAllAssociative(); $stmt->closeCursor(); // at this point the result is cached .. warning:: diff --git a/docs/en/reference/data-retrieval-and-manipulation.rst b/docs/en/reference/data-retrieval-and-manipulation.rst index 31397a532b9..e1afd8ec322 100644 --- a/docs/en/reference/data-retrieval-and-manipulation.rst +++ b/docs/en/reference/data-retrieval-and-manipulation.rst @@ -41,7 +41,7 @@ the query until there are no more rows: fetch()) { + while (($row = $stmt->fetchAssociative()) !== false) { echo $row['headline']; } @@ -308,7 +308,7 @@ Prepare a given SQL statement and return the prepare('SELECT * FROM user'); $statement->execute(); - $users = $statement->fetchAll(); + $users = $statement->fetchAllAssociative(); /* array( @@ -346,7 +346,7 @@ parameters to the execute method, then returning the statement: executeQuery('SELECT * FROM user WHERE username = ?', array('jwage')); - $user = $statement->fetch(); + $user = $statement->fetchAssociative(); /* array( @@ -360,15 +360,15 @@ to perform necessary type conversions between actual input parameters and expected database values. See the :ref:`Types ` section for more information. -fetchAll() -~~~~~~~~~~ +fetchAllAssociative() +~~~~~~~~~~~~~~~~~~~~~ Execute the query and fetch all results into an array: .. code-block:: php fetchAll('SELECT * FROM user'); + $users = $conn->fetchAllAssociative('SELECT * FROM user'); /* array( @@ -379,15 +379,15 @@ Execute the query and fetch all results into an array: ) */ -fetchArray() -~~~~~~~~~~~~ +fetchNumeric() +~~~~~~~~~~~~~~ Numeric index retrieval of first result row of the given query: .. code-block:: php fetchArray('SELECT * FROM user WHERE username = ?', array('jwage')); + $user = $conn->fetchNumeric('SELECT * FROM user WHERE username = ?', array('jwage')); /* array( @@ -396,26 +396,26 @@ Numeric index retrieval of first result row of the given query: ) */ -fetchColumn() -~~~~~~~~~~~~~ +fetchOne() +~~~~~~~~~~ -Retrieve only the given column of the first result row. +Retrieve only the value of the first column of the first result row. .. code-block:: php fetchColumn('SELECT username FROM user WHERE id = ?', array(1), 0); + $username = $conn->fetchOne('SELECT username FROM user WHERE id = ?', array(1), 0); echo $username; // jwage -fetchAssoc() -~~~~~~~~~~~~ +fetchAssociative() +~~~~~~~~~~~~~~~~~~ -Retrieve assoc row of the first result row. +Retrieve associative array of the first result row. .. code-block:: php fetchAssoc('SELECT * FROM user WHERE username = ?', array('jwage')); + $user = $conn->fetchAssociative('SELECT * FROM user WHERE username = ?', array('jwage')); /* array( 'username' => 'jwage', diff --git a/src/Cache/ArrayStatement.php b/src/Cache/ArrayStatement.php index 780f113d7c7..f7098df0f07 100644 --- a/src/Cache/ArrayStatement.php +++ b/src/Cache/ArrayStatement.php @@ -2,19 +2,13 @@ namespace Doctrine\DBAL\Cache; -use ArrayIterator; use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\ResultStatement; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; -use InvalidArgumentException; -use IteratorAggregate; -use function array_merge; use function array_values; use function count; use function reset; -class ArrayStatement implements IteratorAggregate, ResultStatement, ForwardCompatibleResultStatement +class ArrayStatement implements ResultStatement { /** @var mixed[] */ private $data; @@ -25,9 +19,6 @@ class ArrayStatement implements IteratorAggregate, ResultStatement, ForwardCompa /** @var int */ private $num = 0; - /** @var int */ - private $defaultFetchMode = FetchMode::MIXED; - /** * @param mixed[] $data */ @@ -59,97 +50,12 @@ public function columnCount() return $this->columnCount; } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->defaultFetchMode = $fetchMode; - - return true; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - $data = $this->fetchAll(); - - return new ArrayIterator($data); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - if (! isset($this->data[$this->num])) { - return false; - } - - $row = $this->data[$this->num++]; - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - if ($fetchMode === FetchMode::ASSOCIATIVE) { - return $row; - } - - if ($fetchMode === FetchMode::NUMERIC) { - return array_values($row); - } - - if ($fetchMode === FetchMode::MIXED) { - return array_merge($row, array_values($row)); - } - - if ($fetchMode === FetchMode::COLUMN) { - return reset($row); - } - - throw new InvalidArgumentException('Invalid fetch-style given for fetching result.'); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $rows = []; - while ($row = $this->fetch($fetchMode)) { - $rows[] = $row; - } - - return $rows; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $row = $this->fetch(FetchMode::NUMERIC); - - // TODO: verify that return false is the correct behavior - return $row[0] ?? false; - } - /** * {@inheritdoc} */ public function fetchNumeric() { - $row = $this->doFetch(); + $row = $this->fetch(); if ($row === false) { return false; @@ -163,7 +69,7 @@ public function fetchNumeric() */ public function fetchAssociative() { - return $this->doFetch(); + return $this->fetch(); } /** @@ -171,7 +77,7 @@ public function fetchAssociative() */ public function fetchOne() { - $row = $this->doFetch(); + $row = $this->fetch(); if ($row === false) { return false; @@ -196,10 +102,18 @@ public function fetchAllAssociative() : array return FetchUtils::fetchAllAssociative($this); } + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return FetchUtils::fetchColumn($this); + } + /** * @return mixed|false */ - private function doFetch() + private function fetch() { if (! isset($this->data[$this->num])) { return false; diff --git a/src/Cache/ResultCacheStatement.php b/src/Cache/ResultCacheStatement.php index fba1e1ecef7..cf46779a143 100644 --- a/src/Cache/ResultCacheStatement.php +++ b/src/Cache/ResultCacheStatement.php @@ -2,20 +2,12 @@ namespace Doctrine\DBAL\Cache; -use ArrayIterator; use Doctrine\Common\Cache\Cache; use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\ResultStatement; -use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; -use InvalidArgumentException; -use IteratorAggregate; -use function array_merge; +use function array_map; use function array_values; -use function assert; -use function reset; /** * Cache statement for SQL results. @@ -30,7 +22,7 @@ * Also you have to realize that the cache will load the whole result into memory at once to ensure 2. * This means that the memory usage for cached results might increase by using this feature. */ -class ResultCacheStatement implements IteratorAggregate, ResultStatement, ForwardCompatibleResultStatement +class ResultCacheStatement implements ResultStatement { /** @var Cache */ private $resultCache; @@ -54,12 +46,9 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement, Forwar */ private $emptied = false; - /** @var mixed[] */ + /** @var array> */ private $data; - /** @var int */ - private $defaultFetchMode = FetchMode::MIXED; - /** * @param string $cacheKey * @param string $realKey @@ -105,112 +94,12 @@ public function columnCount() return $this->statement->columnCount(); } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->defaultFetchMode = $fetchMode; - - return true; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - $data = $this->fetchAll(); - - return new ArrayIterator($data); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - if ($this->data === null) { - $this->data = []; - } - - $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); - - if ($row !== false) { - $this->data[] = $row; - - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - if ($fetchMode === FetchMode::ASSOCIATIVE) { - return $row; - } - - if ($fetchMode === FetchMode::NUMERIC) { - return array_values($row); - } - - if ($fetchMode === FetchMode::MIXED) { - return array_merge($row, array_values($row)); - } - - if ($fetchMode === FetchMode::COLUMN) { - return reset($row); - } - - throw new InvalidArgumentException('Invalid fetch-style given for caching result.'); - } - - $this->emptied = true; - - return false; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $data = $this->statement->fetchAll($fetchMode); - - if ($fetchMode === FetchMode::COLUMN) { - foreach ($data as $key => $value) { - $data[$key] = [$value]; - } - } - - $this->data = $data; - $this->emptied = true; - - return $this->data; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $row = $this->fetch(FetchMode::NUMERIC); - - // TODO: verify that return false is the correct behavior - return $row[0] ?? false; - } - /** * {@inheritdoc} */ public function fetchNumeric() { - $row = $this->doFetch(); + $row = $this->fetch(); if ($row === false) { return false; @@ -224,7 +113,7 @@ public function fetchNumeric() */ public function fetchAssociative() { - return $this->doFetch(); + return $this->fetch(); } /** @@ -240,13 +129,11 @@ public function fetchOne() */ public function fetchAllNumeric() : array { - if ($this->statement instanceof ForwardCompatibleResultStatement) { - $data = $this->statement->fetchAllAssociative(); - } else { - $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); - } + $this->store( + $this->statement->fetchAllAssociative() + ); - return $this->store($data); + return array_map('array_values', $this->data); } /** @@ -254,31 +141,19 @@ public function fetchAllNumeric() : array */ public function fetchAllAssociative() : array { - if ($this->statement instanceof ForwardCompatibleResultStatement) { - $data = $this->statement->fetchAllAssociative(); - } else { - $data = $this->statement->fetchAll(FetchMode::ASSOCIATIVE); - } + $this->store( + $this->statement->fetchAllAssociative() + ); - return $this->store($data); + return $this->data; } /** - * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement - * executed by the corresponding object. - * - * If the last SQL statement executed by the associated Statement object was a SELECT statement, - * some databases may return the number of rows returned by that statement. However, - * this behaviour is not guaranteed for all databases and should not be - * relied on for portable applications. - * - * @return int The number of rows. + * {@inheritdoc} */ - public function rowCount() : int + public function fetchColumn() : array { - assert($this->statement instanceof Statement); - - return $this->statement->rowCount(); + return FetchUtils::fetchColumn($this); } /** @@ -286,17 +161,13 @@ public function rowCount() : int * * @throws DriverException */ - private function doFetch() + private function fetch() { if ($this->data === null) { $this->data = []; } - if ($this->statement instanceof ForwardCompatibleResultStatement) { - $row = $this->statement->fetchAssociative(); - } else { - $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); - } + $row = $this->statement->fetchAssociative(); if ($row !== false) { $this->data[] = $row; @@ -310,19 +181,11 @@ private function doFetch() } /** - * @param array> $data - * - * @return array> + * @param array> $data */ - private function store(array $data) : array + private function store(array $data) : void { - foreach ($data as $key => $value) { - $data[$key] = [$value]; - } - $this->data = $data; $this->emptied = true; - - return $this->data; } } diff --git a/src/Connection.php b/src/Connection.php index 9b8a4b62c6f..105a1247b03 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -14,7 +14,6 @@ use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Exception\InvalidArgumentException; -use Doctrine\DBAL\ForwardCompatibility\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Doctrine\DBAL\Query\QueryBuilder; @@ -168,9 +167,6 @@ class Connection implements DriverConnection */ private $isRollbackOnly = false; - /** @var int */ - protected $defaultFetchMode = FetchMode::ASSOCIATIVE; - /** * Initializes a new instance of the Connection class. * @@ -522,75 +518,6 @@ public function setAutoCommit($autoCommit) $this->commitAll(); } - /** - * Sets the fetch mode. - * - * @deprecated Use one of the fetch- or iterate-related methods. - * - * @param int $fetchMode - * - * @return void - */ - public function setFetchMode($fetchMode) - { - $this->defaultFetchMode = $fetchMode; - } - - /** - * Prepares and executes an SQL query and returns the first row of the result - * as an associative array. - * - * @deprecated Use fetchAllAssociative() - * - * @param string $statement The SQL query. - * @param mixed[] $params The query parameters. - * @param int[]|string[] $types The query parameter types. - * - * @return mixed[]|false False is returned if no rows are found. - * - * @throws DBALException - */ - public function fetchAssoc($statement, array $params = [], array $types = []) - { - return $this->executeQuery($statement, $params, $types)->fetch(FetchMode::ASSOCIATIVE); - } - - /** - * Prepares and executes an SQL query and returns the first row of the result - * as a numerically indexed array. - * - * @deprecated Use fetchAllNumeric() - * - * @param string $statement The SQL query to be executed. - * @param mixed[] $params The prepared statement params. - * @param int[]|string[] $types The query parameter types. - * - * @return mixed[]|false False is returned if no rows are found. - */ - public function fetchArray($statement, array $params = [], array $types = []) - { - return $this->executeQuery($statement, $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. - * - * @deprecated Use fetchOne() instead. - * - * @param string $statement The SQL query to be executed. - * @param mixed[] $params The prepared statement params. - * @param int[]|string[] $types The query parameter types. - * - * @return mixed|false False is returned if no rows are found. - * - * @throws DBALException - */ - public function fetchColumn($statement, array $params = [], array $types = []) - { - return $this->executeQuery($statement, $params, $types)->fetchColumn(); - } - /** * Prepares and executes an SQL query and returns the first row of the result * as an associative array. @@ -606,13 +533,7 @@ public function fetchColumn($statement, array $params = [], array $types = []) public function fetchAssociative(string $query, array $params = [], array $types = []) { try { - $stmt = $this->executeQuery($query, $params, $types); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchAssociative(); - } - - return $stmt->fetch(FetchMode::ASSOCIATIVE); + return $this->executeQuery($query, $params, $types)->fetchAssociative(); } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); } @@ -633,13 +554,7 @@ public function fetchAssociative(string $query, array $params = [], array $types public function fetchNumeric(string $query, array $params = [], array $types = []) { try { - $stmt = $this->executeQuery($query, $params, $types); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchNumeric(); - } - - return $stmt->fetch(FetchMode::NUMERIC); + return $this->executeQuery($query, $params, $types)->fetchNumeric(); } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); } @@ -660,13 +575,7 @@ public function fetchNumeric(string $query, array $params = [], array $types = [ public function fetchOne(string $query, array $params = [], array $types = []) { try { - $stmt = $this->executeQuery($query, $params, $types); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchOne(); - } - - return $stmt->fetch(FetchMode::COLUMN); + return $this->executeQuery($query, $params, $types)->fetchOne(); } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); } @@ -917,68 +826,60 @@ public function quote($input, $type = ParameterType::STRING) } /** - * Prepares and executes an SQL query and returns the result as an associative array. + * Prepares and executes an SQL query and returns the result as an array of numeric arrays. * - * @deprecated Use fetchAllAssociative() + * @param string $query The SQL query. + * @param array|array $params The query parameters. + * @param array|array $types The query parameter types. * - * @param string $sql The SQL query. - * @param mixed[] $params The query parameters. - * @param int[]|string[] $types The query parameter types. + * @return array> * - * @return mixed[] + * @throws DBALException */ - public function fetchAll($sql, array $params = [], $types = []) + public function fetchAllNumeric(string $query, array $params = [], array $types = []) : array { - return $this->executeQuery($sql, $params, $types)->fetchAll(); + try { + return $this->executeQuery($query, $params, $types)->fetchAllNumeric(); + } catch (Throwable $e) { + throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); + } } /** - * Prepares and executes an SQL query and returns the result as an array of numeric arrays. + * Prepares and executes an SQL query and returns the result as an array of associative arrays. * * @param string $query The SQL query. * @param array|array $params The query parameters. * @param array|array $types The query parameter types. * - * @return array> + * @return array> * * @throws DBALException */ - public function fetchAllNumeric(string $query, array $params = [], array $types = []) : array + public function fetchAllAssociative(string $query, array $params = [], array $types = []) : array { try { - $stmt = $this->executeQuery($query, $params, $types); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchAllNumeric(); - } - - return $stmt->fetchAll(FetchMode::NUMERIC); + return $this->executeQuery($query, $params, $types)->fetchAllAssociative(); } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); } } /** - * Prepares and executes an SQL query and returns the result as an array of associative arrays. + * Prepares and executes an SQL query and returns the result as an array of the first column values. * * @param string $query The SQL query. * @param array|array $params The query parameters. * @param array|array $types The query parameter types. * - * @return array> + * @return array * * @throws DBALException */ - public function fetchAllAssociative(string $query, array $params = [], array $types = []) : array + public function fetchColumn(string $query, array $params = [], array $types = []) : array { try { - $stmt = $this->executeQuery($query, $params, $types); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchAllAssociative(); - } - - return $stmt->fetchAll(FetchMode::ASSOCIATIVE); + return $this->executeQuery($query, $params, $types)->fetchColumn(); } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); } @@ -1000,12 +901,8 @@ public function iterateNumeric(string $query, array $params = [], array $types = try { $stmt = $this->executeQuery($query, $params, $types); - if ($stmt instanceof ForwardCompatibleResultStatement) { - yield from $stmt->iterateNumeric(); - } else { - while (($row = $stmt->fetch(FetchMode::NUMERIC)) !== false) { - yield $row; - } + while (($row = $stmt->fetchNumeric()) !== false) { + yield $row; } } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); @@ -1028,12 +925,8 @@ public function iterateAssociative(string $query, array $params = [], array $typ try { $stmt = $this->executeQuery($query, $params, $types); - if ($stmt instanceof ForwardCompatibleResultStatement) { - yield from $stmt->iterateAssociative(); - } else { - while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { - yield $row; - } + while (($row = $stmt->fetchAssociative()) !== false) { + yield $row; } } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); @@ -1056,12 +949,8 @@ public function iterateColumn(string $query, array $params = [], array $types = try { $stmt = $this->executeQuery($query, $params, $types); - if ($stmt instanceof ForwardCompatibleResultStatement) { - yield from $stmt->iterateColumn(); - } else { - while (($value = $stmt->fetch(FetchMode::COLUMN)) !== false) { - yield $value; - } + while (($value = $stmt->fetchOne()) !== false) { + yield $value; } } catch (Throwable $e) { throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); @@ -1078,14 +967,10 @@ public function iterateColumn(string $query, array $params = [], array $types = public function prepare(string $sql) : DriverStatement { try { - $stmt = new Statement($sql, $this); + return new Statement($sql, $this); } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } - - $stmt->setFetchMode($this->defaultFetchMode); - - return $stmt; } /** @@ -1134,8 +1019,6 @@ public function executeQuery(string $query, array $params = [], $types = [], ?Qu throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); } - $stmt->setFetchMode($this->defaultFetchMode); - if ($logger !== null) { $logger->stopQuery(); } @@ -1182,8 +1065,6 @@ public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qc $stmt = new ResultCacheStatement($this->executeQuery($query, $params, $types), $resultCache, $cacheKey, $realKey, $qcp->getLifetime()); } - $stmt->setFetchMode($this->defaultFetchMode); - return $stmt; } @@ -1202,8 +1083,6 @@ public function query(string $sql) : ResultStatement throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql); } - $statement->setFetchMode($this->defaultFetchMode); - if ($logger !== null) { $logger->stopQuery(); } diff --git a/src/Connections/MasterSlaveConnection.php b/src/Connections/MasterSlaveConnection.php index 7cdf592a512..0409f139408 100644 --- a/src/Connections/MasterSlaveConnection.php +++ b/src/Connections/MasterSlaveConnection.php @@ -352,8 +352,6 @@ public function query(string $sql) : ResultStatement $statement = $this->_conn->query($sql); - $statement->setFetchMode($this->defaultFetchMode); - if ($logger !== null) { $logger->stopQuery(); } diff --git a/src/Driver/AbstractMySQLDriver.php b/src/Driver/AbstractMySQLDriver.php index bf9e50b91cb..9dc4d702bf3 100644 --- a/src/Driver/AbstractMySQLDriver.php +++ b/src/Driver/AbstractMySQLDriver.php @@ -196,7 +196,7 @@ public function getDatabase(Connection $conn) { $params = $conn->getParams(); - return $params['dbname'] ?? $conn->query('SELECT DATABASE()')->fetchColumn(); + return $params['dbname'] ?? $conn->query('SELECT DATABASE()')->fetchOne(); } /** diff --git a/src/Driver/AbstractPostgreSQLDriver.php b/src/Driver/AbstractPostgreSQLDriver.php index 66e842f926f..408f4d94924 100644 --- a/src/Driver/AbstractPostgreSQLDriver.php +++ b/src/Driver/AbstractPostgreSQLDriver.php @@ -108,7 +108,7 @@ public function getDatabase(Connection $conn) { $params = $conn->getParams(); - return $params['dbname'] ?? $conn->query('SELECT CURRENT_DATABASE()')->fetchColumn(); + return $params['dbname'] ?? $conn->query('SELECT CURRENT_DATABASE()')->fetchOne(); } /** diff --git a/src/Driver/AbstractSQLAnywhereDriver.php b/src/Driver/AbstractSQLAnywhereDriver.php index f43ea633097..da7d1fe93ef 100644 --- a/src/Driver/AbstractSQLAnywhereDriver.php +++ b/src/Driver/AbstractSQLAnywhereDriver.php @@ -105,7 +105,7 @@ public function getDatabase(Connection $conn) { $params = $conn->getParams(); - return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchColumn(); + return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchOne(); } /** diff --git a/src/Driver/AbstractSQLServerDriver.php b/src/Driver/AbstractSQLServerDriver.php index cd549606b0b..d38a61dbc57 100644 --- a/src/Driver/AbstractSQLServerDriver.php +++ b/src/Driver/AbstractSQLServerDriver.php @@ -19,7 +19,7 @@ public function getDatabase(Connection $conn) { $params = $conn->getParams(); - return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchColumn(); + return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchOne(); } /** diff --git a/src/Driver/FetchUtils.php b/src/Driver/FetchUtils.php index 358429255f0..c4d995bc57a 100644 --- a/src/Driver/FetchUtils.php +++ b/src/Driver/FetchUtils.php @@ -4,8 +4,6 @@ namespace Doctrine\DBAL\Driver; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement; - /** * @internal */ @@ -58,4 +56,20 @@ public static function fetchAllAssociative(ResultStatement $stmt) : array return $rows; } + + /** + * @return array + * + * @throws DriverException + */ + public static function fetchColumn(ResultStatement $stmt) : array + { + $rows = []; + + while (($row = $stmt->fetchOne()) !== false) { + $rows[] = $row; + } + + return $rows; + } } diff --git a/src/Driver/IBMDB2/DB2Statement.php b/src/Driver/IBMDB2/DB2Statement.php index d485f8ed576..78a6806cd94 100644 --- a/src/Driver/IBMDB2/DB2Statement.php +++ b/src/Driver/IBMDB2/DB2Statement.php @@ -2,17 +2,14 @@ namespace Doctrine\DBAL\Driver\IBMDB2; +use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\Driver\StatementIterator; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; -use IteratorAggregate; use function assert; use function db2_bind_param; use function db2_execute; use function db2_fetch_array; use function db2_fetch_assoc; -use function db2_fetch_both; use function db2_free_result; use function db2_num_fields; use function db2_num_rows; @@ -32,7 +29,7 @@ use const DB2_PARAM_FILE; use const DB2_PARAM_IN; -class DB2Statement implements IteratorAggregate, Statement +class DB2Statement implements Statement { /** @var resource */ private $stmt; @@ -48,9 +45,6 @@ class DB2Statement implements IteratorAggregate, Statement */ private $lobs = []; - /** @var int */ - private $defaultFetchMode = FetchMode::MIXED; - /** * Indicates whether the statement is in the state when fetching results is possible * @@ -196,99 +190,61 @@ public function execute($params = null) } /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. + * {@inheritDoc} */ - public function setFetchMode($fetchMode) + public function fetchNumeric() { - $this->defaultFetchMode = $fetchMode; - - return true; - } + if (! $this->result) { + return false; + } - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); + return db2_fetch_array($this->stmt); } /** * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. */ - public function fetch($fetchMode = null) + public function fetchAssociative() { - // do not try fetching from the statement if it's not expected to contain result + // do not try fetching from the statement if it's not expected to contain the result // in order to prevent exceptional situation if (! $this->result) { return false; } - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - switch ($fetchMode) { - case FetchMode::COLUMN: - return $this->fetchColumn(); - - case FetchMode::MIXED: - return db2_fetch_both($this->stmt); - - case FetchMode::ASSOCIATIVE: - return db2_fetch_assoc($this->stmt); - - case FetchMode::NUMERIC: - return db2_fetch_array($this->stmt); - - default: - throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.'); - } + return db2_fetch_assoc($this->stmt); } /** * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. */ - public function fetchAll($fetchMode = null) + public function fetchOne() { - $rows = []; - - switch ($fetchMode) { - case FetchMode::COLUMN: - while (($row = $this->fetchColumn()) !== false) { - $rows[] = $row; - } - - break; - - default: - while (($row = $this->fetch($fetchMode)) !== false) { - $rows[] = $row; - } - } - - return $rows; + return FetchUtils::fetchOne($this); } /** * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. */ - public function fetchColumn() + public function fetchAllNumeric() : array { - $row = $this->fetch(FetchMode::NUMERIC); + return FetchUtils::fetchAllNumeric($this); + } - if ($row === false) { - return false; - } + /** + * {@inheritdoc} + */ + public function fetchAllAssociative() : array + { + return FetchUtils::fetchAllAssociative($this); + } - return $row[0] ?? null; + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return FetchUtils::fetchColumn($this); } public function rowCount() : int diff --git a/src/Driver/Mysqli/MysqliStatement.php b/src/Driver/Mysqli/MysqliStatement.php index f9e71042af0..3357a71b72d 100644 --- a/src/Driver/Mysqli/MysqliStatement.php +++ b/src/Driver/Mysqli/MysqliStatement.php @@ -4,12 +4,8 @@ use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\Driver\StatementIterator; use Doctrine\DBAL\Exception\InvalidArgumentException; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; -use IteratorAggregate; use mysqli; use mysqli_stmt; use function array_combine; @@ -25,7 +21,7 @@ use function sprintf; use function str_repeat; -class MysqliStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement +class MysqliStatement implements Statement { /** @var string[] */ protected static $_paramTypeMap = [ @@ -62,9 +58,6 @@ class MysqliStatement implements IteratorAggregate, Statement, ForwardCompatible */ protected $_values = []; - /** @var int */ - protected $_defaultFetchMode = FetchMode::MIXED; - /** * Indicates whether the statement is in the state when fetching results is possible * @@ -308,97 +301,6 @@ private function _fetch() /** * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - // do not try fetching from the statement if it's not expected to contain result - // in order to prevent exceptional situation - if (! $this->result) { - return false; - } - - $fetchMode = $fetchMode ?? $this->_defaultFetchMode; - - if ($fetchMode === FetchMode::COLUMN) { - return $this->fetchColumn(); - } - - $values = $this->_fetch(); - - if ($values === null) { - return false; - } - - if ($values === false) { - throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); - } - - if ($fetchMode === FetchMode::NUMERIC) { - return $values; - } - - assert(is_array($this->_columnNames)); - $assoc = array_combine($this->_columnNames, $values); - assert(is_array($assoc)); - - switch ($fetchMode) { - case FetchMode::ASSOCIATIVE: - return $assoc; - - case FetchMode::MIXED: - return $assoc + $values; - - default: - throw new MysqliException(sprintf("Unknown fetch type '%s'", $fetchMode)); - } - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $fetchMode = $fetchMode ?? $this->_defaultFetchMode; - - $rows = []; - - if ($fetchMode === FetchMode::COLUMN) { - while (($row = $this->fetchColumn()) !== false) { - $rows[] = $row; - } - } else { - while (($row = $this->fetch($fetchMode)) !== false) { - $rows[] = $row; - } - } - - return $rows; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $row = $this->fetch(FetchMode::NUMERIC); - - if ($row === false) { - return false; - } - - return $row[0] ?? null; - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. */ public function fetchNumeric() { @@ -463,6 +365,14 @@ public function fetchAllAssociative() : array return FetchUtils::fetchAllAssociative($this); } + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return FetchUtils::fetchColumn($this); + } + /** * {@inheritdoc} */ @@ -490,26 +400,4 @@ public function columnCount() { return $this->_stmt->field_count; } - - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->_defaultFetchMode = $fetchMode; - - return true; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } } diff --git a/src/Driver/OCI8/OCI8Connection.php b/src/Driver/OCI8/OCI8Connection.php index efdb3b4d9a8..479c1ec9e92 100644 --- a/src/Driver/OCI8/OCI8Connection.php +++ b/src/Driver/OCI8/OCI8Connection.php @@ -144,9 +144,7 @@ public function lastInsertId($name = null) return false; } - $sql = 'SELECT ' . $name . '.CURRVAL FROM DUAL'; - $stmt = $this->query($sql); - $result = $stmt->fetchColumn(); + $result = $this->query('SELECT ' . $name . '.CURRVAL FROM DUAL')->fetchOne(); if ($result === false) { throw new OCI8Exception('lastInsertId failed: Query was executed but no result was returned.'); diff --git a/src/Driver/OCI8/OCI8Statement.php b/src/Driver/OCI8/OCI8Statement.php index 2383dd307ed..9e36aafd4e0 100644 --- a/src/Driver/OCI8/OCI8Statement.php +++ b/src/Driver/OCI8/OCI8Statement.php @@ -4,12 +4,7 @@ use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\Driver\StatementIterator; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; -use InvalidArgumentException; -use IteratorAggregate; use function assert; use function count; use function implode; @@ -32,7 +27,6 @@ use const OCI_ASSOC; use const OCI_B_BIN; use const OCI_B_BLOB; -use const OCI_BOTH; use const OCI_D_LOB; use const OCI_FETCHSTATEMENT_BY_COLUMN; use const OCI_FETCHSTATEMENT_BY_ROW; @@ -46,7 +40,7 @@ /** * The OCI8 implementation of the Statement interface. */ -class OCI8Statement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement +class OCI8Statement implements Statement { /** @var resource */ protected $_dbh; @@ -64,17 +58,6 @@ class OCI8Statement implements IteratorAggregate, Statement, ForwardCompatibleRe */ protected static $_PARAM = ':param'; - /** @var int[] */ - protected static $fetchModeMap = [ - FetchMode::MIXED => OCI_BOTH, - FetchMode::ASSOCIATIVE => OCI_ASSOC, - FetchMode::NUMERIC => OCI_NUM, - FetchMode::COLUMN => OCI_NUM, - ]; - - /** @var int */ - protected $_defaultFetchMode = FetchMode::MIXED; - /** @var string[] */ protected $_paramMap = []; @@ -380,127 +363,6 @@ public function execute($params = null) return $ret; } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->_defaultFetchMode = $fetchMode; - - return true; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - // do not try fetching from the statement if it's not expected to contain result - // in order to prevent exceptional situation - if (! $this->result) { - return false; - } - - $fetchMode = $fetchMode ?? $this->_defaultFetchMode; - - if ($fetchMode === FetchMode::COLUMN) { - return $this->fetchColumn(); - } - - if (! isset(self::$fetchModeMap[$fetchMode])) { - throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); - } - - return oci_fetch_array( - $this->_sth, - self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | OCI_RETURN_LOBS - ); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $fetchMode = $fetchMode ?? $this->_defaultFetchMode; - - $result = []; - - if (! isset(self::$fetchModeMap[$fetchMode])) { - throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); - } - - if (self::$fetchModeMap[$fetchMode] === OCI_BOTH) { - while ($row = $this->fetch($fetchMode)) { - $result[] = $row; - } - } else { - $fetchStructure = OCI_FETCHSTATEMENT_BY_ROW; - - if ($fetchMode === FetchMode::COLUMN) { - $fetchStructure = OCI_FETCHSTATEMENT_BY_COLUMN; - } - - // do not try fetching from the statement if it's not expected to contain result - // in order to prevent exceptional situation - if (! $this->result) { - return []; - } - - oci_fetch_all( - $this->_sth, - $result, - 0, - -1, - self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS - ); - - if ($fetchMode === FetchMode::COLUMN) { - $result = $result[0]; - } - } - - return $result; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - // do not try fetching from the statement if it's not expected to contain result - // in order to prevent exceptional situation - if (! $this->result) { - return false; - } - - $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS); - - if ($row === false) { - return false; - } - - return $row[0] ?? null; - } - public function rowCount() : int { $count = oci_num_rows($this->_sth); @@ -517,7 +379,7 @@ public function rowCount() : int */ public function fetchNumeric() { - return $this->doFetch(OCI_NUM); + return $this->fetch(OCI_NUM); } /** @@ -525,7 +387,7 @@ public function fetchNumeric() */ public function fetchAssociative() { - return $this->doFetch(OCI_ASSOC); + return $this->fetch(OCI_ASSOC); } /** @@ -541,7 +403,7 @@ public function fetchOne() */ public function fetchAllNumeric() : array { - return $this->doFetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW); + return $this->fetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW); } /** @@ -549,13 +411,21 @@ public function fetchAllNumeric() : array */ public function fetchAllAssociative() : array { - return $this->doFetchAll(OCI_ASSOC, OCI_FETCHSTATEMENT_BY_ROW); + return $this->fetchAll(OCI_ASSOC, OCI_FETCHSTATEMENT_BY_ROW); + } + + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return $this->fetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_COLUMN)[0]; } /** * @return mixed|false */ - private function doFetch(int $mode) + private function fetch(int $mode) { // do not try fetching from the statement if it's not expected to contain the result // in order to prevent exceptional situation @@ -572,7 +442,7 @@ private function doFetch(int $mode) /** * @return array */ - private function doFetchAll(int $mode, int $fetchStructure) : array + private function fetchAll(int $mode, int $fetchStructure) : array { // do not try fetching from the statement if it's not expected to contain the result // in order to prevent exceptional situation diff --git a/src/Driver/PDOSqlsrv/Connection.php b/src/Driver/PDOSqlsrv/Connection.php index b1aacf5aa0d..2e3412dd427 100644 --- a/src/Driver/PDOSqlsrv/Connection.php +++ b/src/Driver/PDOSqlsrv/Connection.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOStatement; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use function strpos; use function substr; @@ -26,11 +25,7 @@ public function lastInsertId($name = null) $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); $stmt->execute([$name]); - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchOne(); - } - - return $stmt->fetchColumn(); + return $stmt->fetchOne(); } /** diff --git a/src/Driver/PDOStatement.php b/src/Driver/PDOStatement.php index 6e176caa628..e7278ae974c 100644 --- a/src/Driver/PDOStatement.php +++ b/src/Driver/PDOStatement.php @@ -2,11 +2,8 @@ namespace Doctrine\DBAL\Driver; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use InvalidArgumentException; -use IteratorAggregate; use PDO; use function array_slice; use function assert; @@ -17,7 +14,7 @@ * The PDO implementation of the Statement interface. * Used by all PDO-based drivers. */ -class PDOStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement +class PDOStatement implements Statement { private const PARAM_TYPE_MAP = [ ParameterType::NULL => PDO::PARAM_NULL, @@ -28,13 +25,6 @@ class PDOStatement implements IteratorAggregate, Statement, ForwardCompatibleRes ParameterType::BOOLEAN => PDO::PARAM_BOOL, ]; - private const FETCH_MODE_MAP = [ - FetchMode::ASSOCIATIVE => PDO::FETCH_ASSOC, - FetchMode::NUMERIC => PDO::FETCH_NUM, - FetchMode::MIXED => PDO::FETCH_BOTH, - FetchMode::COLUMN => PDO::FETCH_COLUMN, - ]; - /** @var \PDOStatement */ private $stmt; @@ -43,22 +33,6 @@ public function __construct(\PDOStatement $stmt) $this->stmt = $stmt; } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $fetchMode = $this->convertFetchMode($fetchMode); - - try { - return $this->stmt->setFetchMode($fetchMode); - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - } - /** * {@inheritdoc} */ @@ -132,64 +106,6 @@ public function rowCount() : int return $this->stmt->rowCount(); } - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - try { - if ($fetchMode === null) { - return $this->stmt->fetch(); - } - - return $this->stmt->fetch( - $this->convertFetchMode($fetchMode) - ); - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - try { - if ($fetchMode === null) { - $data = $this->stmt->fetchAll(); - } else { - $data = $this->stmt->fetchAll( - $this->convertFetchMode($fetchMode) - ); - } - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - - assert(is_array($data)); - - return $data; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - try { - return $this->stmt->fetchColumn(); - } catch (\PDOException $exception) { - throw new PDOException($exception); - } - } - /** * {@inheritdoc} */ @@ -231,38 +147,56 @@ public function fetchAllAssociative() : array } /** - * Converts DBAL parameter type to PDO parameter type + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return $this->fetchAll(PDO::FETCH_COLUMN); + } + + /** + * @return mixed|false * - * @param int $type Parameter type + * @throws PDOException */ - private function convertParamType(int $type) : int + private function fetch(int $mode) { - if (! isset(self::PARAM_TYPE_MAP[$type])) { - throw new InvalidArgumentException('Invalid parameter type: ' . $type); + try { + return $this->stmt->fetch($mode); + } catch (\PDOException $exception) { + throw new PDOException($exception); } - - return self::PARAM_TYPE_MAP[$type]; } /** - * Converts DBAL fetch mode to PDO fetch mode + * @return array * - * @param int $fetchMode Fetch mode + * @throws PDOException */ - private function convertFetchMode(int $fetchMode) : int + private function fetchAll(int $mode) : array { - if (! isset(self::FETCH_MODE_MAP[$fetchMode])) { - throw new InvalidArgumentException('Invalid fetch mode: ' . $fetchMode); + try { + $data = $this->stmt->fetchAll($mode); + } catch (\PDOException $exception) { + throw new PDOException($exception); } - return self::FETCH_MODE_MAP[$fetchMode]; + assert(is_array($data)); + + return $data; } /** - * {@inheritdoc} + * Converts DBAL parameter type to PDO parameter type + * + * @param int $type Parameter type */ - public function getIterator() + private function convertParamType(int $type) : int { - yield from $this->stmt; + if (! isset(self::PARAM_TYPE_MAP[$type])) { + throw new InvalidArgumentException('Invalid parameter type: ' . $type); + } + + return self::PARAM_TYPE_MAP[$type]; } } diff --git a/src/Driver/ResultStatement.php b/src/Driver/ResultStatement.php index 80c4f0cd0a2..8fe6be076b4 100644 --- a/src/Driver/ResultStatement.php +++ b/src/Driver/ResultStatement.php @@ -1,13 +1,13 @@ |false * - * @return bool + * @throws DriverException */ - public function setFetchMode($fetchMode); + public function fetchNumeric(); /** - * Returns the next row of a result set. + * Returns the next row of a result set as an associative array or FALSE if there are no more rows. * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. + * @return array|false * - * @param int|null $fetchMode Controls how the next row will be returned to the caller. - * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, - * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. + * @throws DriverException + */ + public function fetchAssociative(); + + /** + * Returns the first value of the next row of a result set or FALSE if there are no more rows. * - * @return mixed The return value of this method on success depends on the fetch mode. In all cases, FALSE is - * returned on failure. + * @return mixed|false + * + * @throws DriverException */ - public function fetch($fetchMode = null); + public function fetchOne(); /** - * Returns an array containing all of the result set rows. + * Returns an array containing all of the result set rows represented as numeric arrays. + * + * @return array> * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. + * @throws DriverException + */ + public function fetchAllNumeric() : array; + + /** + * Returns an array containing all of the result set rows represented as associative arrays. * - * @param int|null $fetchMode Controls how the next row will be returned to the caller. - * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, - * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. + * @return array> * - * @return mixed[] + * @throws DriverException */ - public function fetchAll($fetchMode = null); + public function fetchAllAssociative() : array; /** - * Returns a single column from the next row of a result set or FALSE if there are no more rows. + * Returns an array containing the values of the first column of the result set. * - * @deprecated Use fetchOne() instead. + * @return array * - * @return mixed|false A single column in the next row of a result set, or FALSE if there are no more rows. + * @throws DriverException */ - public function fetchColumn(); + public function fetchColumn() : array; } diff --git a/src/Driver/SQLAnywhere/SQLAnywhereConnection.php b/src/Driver/SQLAnywhere/SQLAnywhereConnection.php index d07711658e9..3c7fdc2af83 100644 --- a/src/Driver/SQLAnywhere/SQLAnywhereConnection.php +++ b/src/Driver/SQLAnywhere/SQLAnywhereConnection.php @@ -5,7 +5,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use function assert; use function is_float; @@ -101,14 +100,7 @@ public function exec(string $statement) : int */ public function getServerVersion() { - $stmt = $this->query("SELECT PROPERTY('ProductVersion')"); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - $version = $stmt->fetchOne(); - } else { - $version = $stmt->fetchColumn(); - } - + $version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchOne(); assert(is_string($version)); return $version; @@ -123,13 +115,7 @@ public function lastInsertId($name = null) return sasql_insert_id($this->connection); } - $stmt = $this->query('SELECT ' . $name . '.CURRVAL'); - - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchOne(); - } - - return $stmt->fetchColumn(); + return $this->query('SELECT ' . $name . '.CURRVAL')->fetchOne(); } public function prepare(string $sql) : DriverStatement diff --git a/src/Driver/SQLAnywhere/SQLAnywhereStatement.php b/src/Driver/SQLAnywhere/SQLAnywhereStatement.php index 4c9d86fa77d..d23348f74d0 100644 --- a/src/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/src/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -5,16 +5,11 @@ use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\Driver\StatementIterator; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; -use IteratorAggregate; use function array_key_exists; use function assert; use function is_int; use function is_resource; -use function sasql_fetch_array; use function sasql_fetch_assoc; use function sasql_fetch_row; use function sasql_prepare; @@ -24,19 +19,15 @@ use function sasql_stmt_field_count; use function sasql_stmt_reset; use function sasql_stmt_result_metadata; -use const SASQL_BOTH; /** * SAP SQL Anywhere implementation of the Statement interface. */ -class SQLAnywhereStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement +class SQLAnywhereStatement implements Statement { /** @var resource The connection resource. */ private $conn; - /** @var int Default fetch mode to use. */ - private $defaultFetchMode = FetchMode::MIXED; - /** @var resource|null The result set resource to fetch. */ private $result; @@ -167,91 +158,8 @@ public function execute($params = null) /** * {@inheritdoc} * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - * * @throws SQLAnywhereException */ - public function fetch($fetchMode = null) - { - if (! is_resource($this->result)) { - return false; - } - - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - switch ($fetchMode) { - case FetchMode::COLUMN: - return $this->fetchColumn(); - - case FetchMode::ASSOCIATIVE: - return sasql_fetch_assoc($this->result); - - case FetchMode::MIXED: - return sasql_fetch_array($this->result, SASQL_BOTH); - - case FetchMode::NUMERIC: - return sasql_fetch_row($this->result); - - default: - throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode); - } - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $rows = []; - - switch ($fetchMode) { - case FetchMode::COLUMN: - while (($row = $this->fetchColumn()) !== false) { - $rows[] = $row; - } - - break; - - default: - while (($row = $this->fetch($fetchMode)) !== false) { - $rows[] = $row; - } - } - - return $rows; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $row = $this->fetch(FetchMode::NUMERIC); - - if ($row === false) { - return false; - } - - return $row[0] ?? null; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } - - /** - * {@inheritDoc} - */ public function fetchNumeric() { if (! is_resource($this->result)) { @@ -303,20 +211,18 @@ public function fetchAllAssociative() : array return FetchUtils::fetchAllAssociative($this); } - public function rowCount() : int - { - return sasql_stmt_affected_rows($this->stmt); - } - /** - * {@inheritdoc} + * @return array * - * @deprecated Use one of the fetch- or iterate-related methods. + * @throws DriverException */ - public function setFetchMode($fetchMode) + public function fetchColumn() : array { - $this->defaultFetchMode = $fetchMode; + return FetchUtils::fetchColumn($this); + } - return true; + public function rowCount() : int + { + return sasql_stmt_affected_rows($this->stmt); } } diff --git a/src/Driver/SQLSrv/SQLSrvConnection.php b/src/Driver/SQLSrv/SQLSrvConnection.php index a97f26961ff..3f0f14b7bc6 100644 --- a/src/Driver/SQLSrv/SQLSrvConnection.php +++ b/src/Driver/SQLSrv/SQLSrvConnection.php @@ -5,7 +5,6 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; use function is_float; use function is_int; @@ -129,11 +128,7 @@ public function lastInsertId($name = null) $stmt = $this->query('SELECT @@IDENTITY'); } - if ($stmt instanceof ForwardCompatibleResultStatement) { - return $stmt->fetchOne(); - } - - return $stmt->fetchColumn(); + return $stmt->fetchOne(); } /** diff --git a/src/Driver/SQLSrv/SQLSrvStatement.php b/src/Driver/SQLSrv/SQLSrvStatement.php index 00a69bae3fe..7454d91e64a 100644 --- a/src/Driver/SQLSrv/SQLSrvStatement.php +++ b/src/Driver/SQLSrv/SQLSrvStatement.php @@ -4,11 +4,7 @@ use Doctrine\DBAL\Driver\FetchUtils; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\Driver\StatementIterator; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; -use IteratorAggregate; use function is_int; use function is_numeric; use function sqlsrv_execute; @@ -25,14 +21,13 @@ use function stripos; use const SQLSRV_ENC_BINARY; use const SQLSRV_FETCH_ASSOC; -use const SQLSRV_FETCH_BOTH; use const SQLSRV_FETCH_NUMERIC; use const SQLSRV_PARAM_IN; /** * SQL Server Statement. */ -class SQLSrvStatement implements IteratorAggregate, Statement, ForwardCompatibleResultStatement +final class SQLSrvStatement implements Statement { /** * The SQLSRV Resource. @@ -69,24 +64,6 @@ class SQLSrvStatement implements IteratorAggregate, Statement, ForwardCompatible */ private $types = []; - /** - * Translations. - * - * @var int[] - */ - private static $fetchMap = [ - FetchMode::MIXED => SQLSRV_FETCH_BOTH, - FetchMode::ASSOCIATIVE => SQLSRV_FETCH_ASSOC, - FetchMode::NUMERIC => SQLSRV_FETCH_NUMERIC, - ]; - - /** - * The fetch style. - * - * @var int - */ - private $defaultFetchMode = FetchMode::MIXED; - /** * The last insert ID. * @@ -279,104 +256,12 @@ private function prepare() return $stmt; } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->defaultFetchMode = $fetchMode; - - return true; - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - * - * @throws SQLSrvException - */ - public function fetch($fetchMode = null) - { - // do not try fetching from the statement if it's not expected to contain result - // in order to prevent exceptional situation - if ($this->stmt === null || ! $this->result) { - return false; - } - - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - if ($fetchMode === FetchMode::COLUMN) { - return $this->fetchColumn(); - } - - if (isset(self::$fetchMap[$fetchMode])) { - return sqlsrv_fetch_array($this->stmt, self::$fetchMap[$fetchMode]) ?? false; - } - - throw new SQLSrvException('Fetch mode is not supported!'); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $rows = []; - - switch ($fetchMode) { - case FetchMode::COLUMN: - while (($row = $this->fetchColumn()) !== false) { - $rows[] = $row; - } - - break; - - default: - while (($row = $this->fetch($fetchMode)) !== false) { - $rows[] = $row; - } - } - - return $rows; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $row = $this->fetch(FetchMode::NUMERIC); - - if ($row === false) { - return false; - } - - return $row[0] ?? null; - } - /** * {@inheritdoc} */ public function fetchNumeric() { - return $this->doFetch(SQLSRV_FETCH_NUMERIC); + return $this->fetch(SQLSRV_FETCH_NUMERIC); } /** @@ -384,7 +269,7 @@ public function fetchNumeric() */ public function fetchAssociative() { - return $this->doFetch(SQLSRV_FETCH_ASSOC); + return $this->fetch(SQLSRV_FETCH_ASSOC); } /** @@ -411,6 +296,14 @@ public function fetchAllAssociative() : array return FetchUtils::fetchAllAssociative($this); } + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return FetchUtils::fetchColumn($this); + } + public function rowCount() : int { if ($this->stmt === null) { @@ -429,7 +322,7 @@ public function rowCount() : int /** * @return mixed|false */ - private function doFetch(int $fetchType) + private function fetch(int $fetchType) { // do not try fetching from the statement if it's not expected to contain the result // in order to prevent exceptional situation diff --git a/src/Driver/StatementIterator.php b/src/Driver/StatementIterator.php deleted file mode 100644 index cb1ac3a6253..00000000000 --- a/src/Driver/StatementIterator.php +++ /dev/null @@ -1,29 +0,0 @@ -statement = $statement; - } - - /** - * {@inheritdoc} - */ - public function getIterator() - { - while (($result = $this->statement->fetch()) !== false) { - yield $result; - } - } -} diff --git a/src/FetchMode.php b/src/FetchMode.php deleted file mode 100644 index cef84868fe8..00000000000 --- a/src/FetchMode.php +++ /dev/null @@ -1,54 +0,0 @@ -|false - * - * @throws DriverException - */ - public function fetchNumeric(); - - /** - * Returns the next row of a result set as an associative array or FALSE if there are no more rows. - * - * @return array|false - * - * @throws DriverException - */ - public function fetchAssociative(); - - /** - * Returns the first value of the next row of a result set or FALSE if there are no more rows. - * - * @return mixed|false - * - * @throws DriverException - */ - public function fetchOne(); - - /** - * Returns an array containing all of the result set rows represented as numeric arrays. - * - * @return array> - * - * @throws DriverException - */ - public function fetchAllNumeric() : array; - - /** - * Returns an array containing all of the result set rows represented as associative arrays. - * - * @return array> - * - * @throws DriverException - */ - public function fetchAllAssociative() : array; } diff --git a/src/ForwardCompatibility/ResultStatement.php b/src/ForwardCompatibility/ResultStatement.php index 2ba19fa5324..6c7a84ceef7 100644 --- a/src/ForwardCompatibility/ResultStatement.php +++ b/src/ForwardCompatibility/ResultStatement.php @@ -4,39 +4,13 @@ namespace Doctrine\DBAL\ForwardCompatibility; -use Doctrine\DBAL\DBALException; use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as BaseResultStatement; -use Traversable; /** * Forward compatibility extension for the DBAL ResultStatement interface. + * + * @deprecated */ interface ResultStatement extends BaseResultStatement { - /** - * Returns an iterator over the result set rows represented as numeric arrays. - * - * @return Traversable> - * - * @throws DBALException - */ - public function iterateNumeric() : Traversable; - - /** - * Returns an iterator over the result set rows represented as associative arrays. - * - * @return Traversable> - * - * @throws DBALException - */ - public function iterateAssociative() : Traversable; - - /** - * Returns an iterator over the values of the first column of the result set. - * - * @return Traversable - * - * @throws DBALException - */ - public function iterateColumn() : Traversable; } diff --git a/src/Portability/Connection.php b/src/Portability/Connection.php index 8f6bdce9729..ce5575721d6 100644 --- a/src/Portability/Connection.php +++ b/src/Portability/Connection.php @@ -98,28 +98,20 @@ public function getFetchCase() */ 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); - - return $stmt; + return new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); } public function prepare(string $sql) : DriverStatement { - $stmt = new Statement(parent::prepare($sql), $this); - $stmt->setFetchMode($this->defaultFetchMode); - - return $stmt; + return new Statement(parent::prepare($sql), $this); } public function query(string $sql) : ResultStatement { - $connection = $this->getWrappedConnection(); - - $stmt = $connection->query($sql); - $stmt = new Statement($stmt, $this); - $stmt->setFetchMode($this->defaultFetchMode); - - return $stmt; + return new Statement( + $this->getWrappedConnection() + ->query($sql), + $this + ); } } diff --git a/src/Portability/Statement.php b/src/Portability/Statement.php index 1d1a85887c3..816bbad4468 100644 --- a/src/Portability/Statement.php +++ b/src/Portability/Statement.php @@ -4,11 +4,7 @@ use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\Driver\StatementIterator; -use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\ParameterType; -use IteratorAggregate; use function array_change_key_case; use function assert; use function is_string; @@ -17,7 +13,7 @@ /** * Portability wrapper for a Statement. */ -class Statement implements IteratorAggregate, DriverStatement, ForwardCompatibleResultStatement +class Statement implements DriverStatement { /** @var int */ private $portability; @@ -28,9 +24,6 @@ class Statement implements IteratorAggregate, DriverStatement, ForwardCompatible /** @var int */ private $case; - /** @var int */ - private $defaultFetchMode = FetchMode::MIXED; - /** * Wraps Statement and applies portability measures. * @@ -89,79 +82,15 @@ public function execute($params = null) return $this->stmt->execute($params); } - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - $this->defaultFetchMode = $fetchMode; - - return $this->stmt->setFetchMode($fetchMode); - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - $row = $this->stmt->fetch($fetchMode); - - $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) !== 0; - - $row = $this->fixRow($row, $iterateRow, $fixCase); - - return $row; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - $fetchMode = $fetchMode ?? $this->defaultFetchMode; - - $rows = $this->stmt->fetchAll($fetchMode); - - $fixCase = $this->case !== null - && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) - && ($this->portability & Connection::PORTABILITY_FIX_CASE) !== 0; - - return $this->fixResultSet($rows, $fixCase, $fetchMode !== FetchMode::COLUMN); - } - /** * {@inheritdoc} */ public function fetchNumeric() { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - $row = $this->stmt->fetchNumeric(); - } else { - $row = $this->stmt->fetch(FetchMode::NUMERIC); - } - - return $this->fixResult($row, false); + return $this->fixResult( + $this->stmt->fetchAssociative(), + false + ); } /** @@ -169,13 +98,10 @@ public function fetchNumeric() */ public function fetchAssociative() { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - $row = $this->stmt->fetchAssociative(); - } else { - $row = $this->stmt->fetch(FetchMode::ASSOCIATIVE); - } - - return $this->fixResult($row, true); + return $this->fixResult( + $this->stmt->fetchAssociative(), + true + ); } /** @@ -183,11 +109,7 @@ public function fetchAssociative() */ public function fetchOne() { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - $value = $this->stmt->fetchOne(); - } else { - $value = $this->stmt->fetch(FetchMode::COLUMN); - } + $value = $this->stmt->fetchOne(); if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $value === '') { $value = null; @@ -203,13 +125,11 @@ public function fetchOne() */ public function fetchAllNumeric() : array { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - $data = $this->stmt->fetchAllNumeric(); - } else { - $data = $this->stmt->fetchAll(FetchMode::NUMERIC); - } - - return $this->fixResultSet($data, false, true); + return $this->fixResultSet( + $this->stmt->fetchAllNumeric(), + false, + true + ); } /** @@ -217,13 +137,23 @@ public function fetchAllNumeric() : array */ public function fetchAllAssociative() : array { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - $data = $this->stmt->fetchAllAssociative(); - } else { - $data = $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); - } + return $this->fixResultSet( + $this->stmt->fetchAllAssociative(), + true, + true + ); + } - return $this->fixResultSet($data, true, true); + /** + * {@inheritdoc} + */ + public function fetchColumn() : array + { + return $this->fixResultSet( + $this->stmt->fetchColumn(), + true, + false + ); } /** @@ -302,24 +232,6 @@ protected function fixRow($row, $iterateRow, $fixCase) return $row; } - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - $value = $this->stmt->fetchColumn(); - - if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) !== 0 && $value === '') { - $value = null; - } elseif (($this->portability & Connection::PORTABILITY_RTRIM) !== 0 && is_string($value)) { - $value = rtrim($value); - } - - return $value; - } - public function rowCount() : int { assert($this->stmt instanceof DriverStatement); diff --git a/src/ResultStatement.php b/src/ResultStatement.php new file mode 100644 index 00000000000..2602dbbea4d --- /dev/null +++ b/src/ResultStatement.php @@ -0,0 +1,41 @@ +> + * + * @throws DBALException + */ + public function iterateNumeric() : Traversable; + + /** + * Returns an iterator over the result set rows represented as associative arrays. + * + * @return Traversable> + * + * @throws DBALException + */ + public function iterateAssociative() : Traversable; + + /** + * Returns an iterator over the values of the first column of the result set. + * + * @return Traversable + * + * @throws DBALException + */ + public function iterateColumn() : Traversable; +} diff --git a/src/Schema/AbstractSchemaManager.php b/src/Schema/AbstractSchemaManager.php index 07a422a98af..f4b4425c6df 100644 --- a/src/Schema/AbstractSchemaManager.php +++ b/src/Schema/AbstractSchemaManager.php @@ -640,7 +640,7 @@ 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[] */ @@ -668,7 +668,7 @@ protected function _getPortableDatabaseDefinition($database) /** * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition. * - * @param mixed[] $namespace The native DBMS namespace definition. + * @param array $namespace The native DBMS namespace definition. * * @return mixed */ diff --git a/src/Schema/PostgreSqlSchemaManager.php b/src/Schema/PostgreSqlSchemaManager.php index 4c392cf7a2d..d8ab6db1c8c 100644 --- a/src/Schema/PostgreSqlSchemaManager.php +++ b/src/Schema/PostgreSqlSchemaManager.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL\Schema; use Doctrine\DBAL\Exception\DriverException; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; @@ -41,9 +40,7 @@ class PostgreSqlSchemaManager extends AbstractSchemaManager */ public function getSchemaNames() { - $statement = $this->_conn->executeQuery("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'"); - - return $statement->fetchAll(FetchMode::COLUMN); + return $this->_conn->fetchColumn("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'"); } /** @@ -56,7 +53,7 @@ public function getSchemaNames() public function getSchemaSearchPaths() { $params = $this->_conn->getParams(); - $schema = explode(',', $this->_conn->fetchColumn('SHOW search_path')); + $schema = explode(',', $this->_conn->fetchOne('SHOW search_path')); if (isset($params['user'])) { $schema = str_replace('"$user"', $params['user'], $schema); @@ -311,7 +308,7 @@ protected function _getPortableSequenceDefinition($sequence) if (! isset($sequence['increment_by'], $sequence['min_value'])) { /** @var string[] $data */ - $data = $this->_conn->fetchAssoc('SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName)); + $data = $this->_conn->fetchAssociative('SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName)); $sequence += $data; } @@ -532,7 +529,7 @@ public function listTableDetails($tableName) : Table assert($platform instanceof PostgreSQL94Platform); $sql = $platform->getListTableMetadataSQL($tableName); - $tableOptions = $this->_conn->fetchAssoc($sql); + $tableOptions = $this->_conn->fetchAssociative($sql); if ($tableOptions !== false) { $table->addOption('comment', $tableOptions['table_comment']); diff --git a/src/Schema/SqliteSchemaManager.php b/src/Schema/SqliteSchemaManager.php index 8ba8bd372b5..a6d5fcee126 100644 --- a/src/Schema/SqliteSchemaManager.php +++ b/src/Schema/SqliteSchemaManager.php @@ -514,7 +514,7 @@ private function parseColumnCommentFromSQL(string $column, string $sql) : ?strin private function getCreateTableSQL(string $table) : string { - $sql = $this->_conn->fetchColumn( + $sql = $this->_conn->fetchOne( <<<'SQL' SELECT sql FROM ( diff --git a/src/Statement.php b/src/Statement.php index def50288964..0c03298ec9e 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -4,10 +4,8 @@ use Doctrine\DBAL\Driver\DriverException; use Doctrine\DBAL\Driver\Statement as DriverStatement; -use Doctrine\DBAL\ForwardCompatibility\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; -use IteratorAggregate; use Throwable; use Traversable; use function is_string; @@ -16,7 +14,7 @@ * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support * for logging, DBAL mapping types, etc. */ -class Statement implements IteratorAggregate, DriverStatement, ForwardCompatibleResultStatement +class Statement implements DriverStatement, ResultStatement { /** * The SQL statement. @@ -199,53 +197,15 @@ public function columnCount() /** * {@inheritdoc} * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - return $this->stmt->setFetchMode($fetchMode); - } - - /** - * Required by interface IteratorAggregate. - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - * - * {@inheritdoc} - */ - public function getIterator() - { - return $this->stmt; - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - return $this->stmt->fetch($fetchMode); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - return $this->stmt->fetchAll($fetchMode); - } - - /** - * {@inheritDoc} - * - * @deprecated Use fetchOne() instead. + * @throws DBALException */ - public function fetchColumn() + public function fetchNumeric() { - return $this->stmt->fetchColumn(); + try { + return $this->stmt->fetchNumeric(); + } catch (DriverException $e) { + throw DBALException::driverException($this->conn->getDriver(), $e); + } } /** @@ -253,14 +213,10 @@ public function fetchColumn() * * @throws DBALException */ - public function fetchNumeric() + public function fetchAssociative() { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - return $this->stmt->fetchNumeric(); - } - - return $this->stmt->fetch(FetchMode::NUMERIC); + return $this->stmt->fetchAssociative(); } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); } @@ -268,35 +224,25 @@ public function fetchNumeric() /** * {@inheritdoc} - * - * @throws DBALException */ - public function fetchAssociative() + public function fetchOne() { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - return $this->stmt->fetchAssociative(); - } - - return $this->stmt->fetch(FetchMode::ASSOCIATIVE); + return $this->stmt->fetchOne(); } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); } } /** - * {@inheritDoc} + * {@inheritdoc} * * @throws DBALException */ - public function fetchOne() + public function fetchAllNumeric() : array { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - return $this->stmt->fetchOne(); - } - - return $this->stmt->fetch(FetchMode::COLUMN); + return $this->stmt->fetchAllNumeric(); } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); } @@ -307,14 +253,10 @@ public function fetchOne() * * @throws DBALException */ - public function fetchAllNumeric() : array + public function fetchAllAssociative() : array { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - return $this->stmt->fetchAllNumeric(); - } - - return $this->stmt->fetchAll(FetchMode::NUMERIC); + return $this->stmt->fetchAllAssociative(); } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); } @@ -325,14 +267,10 @@ public function fetchAllNumeric() : array * * @throws DBALException */ - public function fetchAllAssociative() : array + public function fetchColumn() : array { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - return $this->stmt->fetchAllAssociative(); - } - - return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); + return $this->stmt->fetchColumn(); } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); } @@ -348,14 +286,8 @@ public function fetchAllAssociative() : array public function iterateNumeric() : Traversable { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - while (($row = $this->stmt->fetchNumeric()) !== false) { - yield $row; - } - } else { - while (($row = $this->stmt->fetch(FetchMode::NUMERIC)) !== false) { - yield $row; - } + while (($row = $this->stmt->fetchNumeric()) !== false) { + yield $row; } } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); @@ -372,14 +304,8 @@ public function iterateNumeric() : Traversable public function iterateAssociative() : Traversable { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - while (($row = $this->stmt->fetchAssociative()) !== false) { - yield $row; - } - } else { - while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) { - yield $row; - } + while (($row = $this->stmt->fetchAssociative()) !== false) { + yield $row; } } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); @@ -396,14 +322,8 @@ public function iterateAssociative() : Traversable public function iterateColumn() : Traversable { try { - if ($this->stmt instanceof ForwardCompatibleResultStatement) { - while (($value = $this->stmt->fetchOne()) !== false) { - yield $value; - } - } else { - while (($value = $this->stmt->fetch(FetchMode::COLUMN)) !== false) { - yield $value; - } + while (($value = $this->stmt->fetchOne()) !== false) { + yield $value; } } catch (DriverException $e) { throw DBALException::driverException($this->conn->getDriver(), $e); diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 9573557840f..544342b9dd5 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -17,7 +17,6 @@ use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Events; use Doctrine\DBAL\Exception\InvalidArgumentException; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Logging\DebugStack; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Platforms\AbstractPlatform; @@ -548,7 +547,7 @@ public function testDeleteWithIsNull() : void ); } - public function testFetchAssoc() : void + public function testFetchAssociative() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; @@ -566,8 +565,7 @@ public function testFetchAssoc() : void $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects(self::once()) - ->method('fetch') - ->with(FetchMode::ASSOCIATIVE) + ->method('fetchAssociative') ->will(self::returnValue($result)); $conn = $this->getMockBuilder(Connection::class) @@ -580,10 +578,10 @@ public function testFetchAssoc() : void ->with($statement, $params, $types) ->will(self::returnValue($driverStatementMock)); - self::assertSame($result, $conn->fetchAssoc($statement, $params, $types)); + self::assertSame($result, $conn->fetchAssociative($statement, $params, $types)); } - public function testFetchArray() : void + public function testFetchNumeric() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; @@ -601,8 +599,7 @@ public function testFetchArray() : void $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects(self::once()) - ->method('fetch') - ->with(FetchMode::NUMERIC) + ->method('fetchNumeric') ->will(self::returnValue($result)); $conn = $this->getMockBuilder(Connection::class) @@ -615,10 +612,10 @@ public function testFetchArray() : void ->with($statement, $params, $types) ->will(self::returnValue($driverStatementMock)); - self::assertSame($result, $conn->fetchArray($statement, $params, $types)); + self::assertSame($result, $conn->fetchNumeric($statement, $params, $types)); } - public function testFetchColumn() : void + public function testFetchOne() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; @@ -636,7 +633,7 @@ public function testFetchColumn() : void $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects(self::once()) - ->method('fetchColumn') + ->method('fetchOne') ->will(self::returnValue($result)); $conn = $this->getMockBuilder(Connection::class) @@ -649,10 +646,10 @@ public function testFetchColumn() : void ->with($statement, $params, $types) ->will(self::returnValue($driverStatementMock)); - self::assertSame($result, $conn->fetchColumn($statement, $params, $types)); + self::assertSame($result, $conn->fetchOne($statement, $params, $types)); } - public function testFetchAll() : void + public function testFetchAllAssociative() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; @@ -670,7 +667,7 @@ public function testFetchAll() : void $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects(self::once()) - ->method('fetchAll') + ->method('fetchAllAssociative') ->will(self::returnValue($result)); $conn = $this->getMockBuilder(Connection::class) @@ -683,7 +680,7 @@ public function testFetchAll() : void ->with($statement, $params, $types) ->will(self::returnValue($driverStatementMock)); - self::assertSame($result, $conn->fetchAll($statement, $params, $types)); + self::assertSame($result, $conn->fetchAllAssociative($statement, $params, $types)); } public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void diff --git a/tests/Driver/AbstractMySQLDriverTest.php b/tests/Driver/AbstractMySQLDriverTest.php index 822d06d2380..c085e998855 100644 --- a/tests/Driver/AbstractMySQLDriverTest.php +++ b/tests/Driver/AbstractMySQLDriverTest.php @@ -29,7 +29,7 @@ public function testReturnsDatabaseName() : void $statement = $this->createMock(ResultStatement::class); $statement->expects(self::once()) - ->method('fetchColumn') + ->method('fetchOne') ->will(self::returnValue($database)); $connection = $this->getConnectionMock(); diff --git a/tests/Driver/AbstractPostgreSQLDriverTest.php b/tests/Driver/AbstractPostgreSQLDriverTest.php index f7e18fca116..1c79c6707c5 100644 --- a/tests/Driver/AbstractPostgreSQLDriverTest.php +++ b/tests/Driver/AbstractPostgreSQLDriverTest.php @@ -27,7 +27,7 @@ public function testReturnsDatabaseName() : void $statement = $this->createMock(ResultStatement::class); $statement->expects(self::once()) - ->method('fetchColumn') + ->method('fetchOne') ->will(self::returnValue($database)); $connection = $this->getConnectionMock(); diff --git a/tests/Driver/StatementIteratorTest.php b/tests/Driver/StatementIteratorTest.php deleted file mode 100644 index 344035c1611..00000000000 --- a/tests/Driver/StatementIteratorTest.php +++ /dev/null @@ -1,106 +0,0 @@ -createPartialMock($class, ['fetch', 'fetchAll', 'fetchColumn']); - $stmt->expects(self::never())->method('fetch'); - $stmt->expects(self::never())->method('fetchAll'); - $stmt->expects(self::never())->method('fetchColumn'); - - $stmt->getIterator(); - } - - public function testIteratorIterationCallsFetchOncePerStep() : void - { - $stmt = $this->createMock(Statement::class); - - $calls = 0; - $this->configureStatement($stmt, $calls); - - $stmtIterator = new StatementIterator($stmt); - - $this->assertIterationCallsFetchOncePerStep($stmtIterator, $calls); - } - - /** - * @dataProvider statementProvider() - */ - public function testStatementIterationCallsFetchOncePerStep(string $class) : void - { - $stmt = $this->createPartialMock($class, ['fetch']); - - $calls = 0; - $this->configureStatement($stmt, $calls); - $this->assertIterationCallsFetchOncePerStep($stmt, $calls); - } - - private function configureStatement(MockObject $stmt, int &$calls) : void - { - $values = ['foo', '', 'bar', '0', 'baz', 0, 'qux', null, 'quz', false, 'impossible']; - $calls = 0; - - $stmt->expects(self::exactly(10)) - ->method('fetch') - ->willReturnCallback(static function () use ($values, &$calls) { - $value = $values[$calls]; - $calls++; - - return $value; - }); - } - - /** - * @param Traversable $iterator - */ - private function assertIterationCallsFetchOncePerStep(Traversable $iterator, int &$calls) : void - { - foreach ($iterator as $i => $_) { - self::assertEquals($i + 1, $calls); - } - } - - /** - * @return string[][] - */ - public static function statementProvider() : iterable - { - if (extension_loaded('ibm_db2')) { - yield [DB2Statement::class]; - } - - yield [MysqliStatement::class]; - - if (extension_loaded('oci8')) { - yield [OCI8Statement::class]; - } - - yield [PortabilityStatement::class]; - yield [SQLAnywhereStatement::class]; - - if (! extension_loaded('sqlsrv')) { - return; - } - - yield [SQLSrvStatement::class]; - } -} diff --git a/tests/Functional/BlobTest.php b/tests/Functional/BlobTest.php index b936b4ebb56..5b37756f91e 100644 --- a/tests/Functional/BlobTest.php +++ b/tests/Functional/BlobTest.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver; use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; @@ -158,7 +157,7 @@ public function testBindParamProcessesStream() : void private function assertBlobContains(string $text) : void { - $rows = $this->connection->query('SELECT blobfield FROM blob_table')->fetchAll(FetchMode::COLUMN); + $rows = $this->connection->query('SELECT blobfield FROM blob_table')->fetchColumn(); self::assertCount(1, $rows); diff --git a/tests/Functional/Connection/BackwardCompatibility/Connection.php b/tests/Functional/Connection/BackwardCompatibility/Connection.php deleted file mode 100644 index 7c752ff5718..00000000000 --- a/tests/Functional/Connection/BackwardCompatibility/Connection.php +++ /dev/null @@ -1,33 +0,0 @@ -connection = DriverManager::getConnection( - array_merge($this->connection->getParams(), [ - 'wrapperClass' => Connection::class, - ]), - $this->connection->getConfiguration(), - $this->connection->getEventManager() - ); - } -} diff --git a/tests/Functional/Connection/BackwardCompatibility/Statement.php b/tests/Functional/Connection/BackwardCompatibility/Statement.php deleted file mode 100644 index e3fb1ab8379..00000000000 --- a/tests/Functional/Connection/BackwardCompatibility/Statement.php +++ /dev/null @@ -1,154 +0,0 @@ -stmt = $stmt; - } - - /** - * {@inheritdoc} - */ - public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->bindParam($column, $variable, $type, $length); - } - - /** - * {@inheritdoc} - */ - public function bindValue($param, $value, $type = ParameterType::STRING) - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->bindValue($param, $value, $type); - } - - /** - * {@inheritdoc} - */ - public function closeCursor() - { - return $this->stmt->closeCursor(); - } - - /** - * {@inheritdoc} - */ - public function columnCount() - { - return $this->stmt->columnCount(); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorCode() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorCode(); - } - - /** - * {@inheritdoc} - * - * @deprecated The error information is available via exceptions. - */ - public function errorInfo() - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->errorInfo(); - } - - /** - * {@inheritdoc} - */ - public function execute($params = null) - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->execute($params); - } - - /** - * {@inheritdoc} - * - * @deprecated Use one of the fetch- or iterate-related methods. - */ - public function setFetchMode($fetchMode) - { - return $this->stmt->setFetchMode($fetchMode); - } - - /** - * {@inheritdoc} - * - * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead. - */ - public function getIterator() - { - return new StatementIterator($this); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. - */ - public function fetch($fetchMode = null) - { - return $this->stmt->fetch($fetchMode); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchColumn() instead. - */ - public function fetchAll($fetchMode = null) - { - return $this->stmt->fetchAll($fetchMode); - } - - /** - * {@inheritdoc} - * - * @deprecated Use fetchOne() instead. - */ - public function fetchColumn() - { - return $this->stmt->fetchColumn(); - } - - public function rowCount() : int - { - assert($this->stmt instanceof DriverStatement); - - return $this->stmt->rowCount(); - } -} diff --git a/tests/Functional/ConnectionTest.php b/tests/Functional/ConnectionTest.php index db9bbeaf6e8..9f39c4854f6 100644 --- a/tests/Functional/ConnectionTest.php +++ b/tests/Functional/ConnectionTest.php @@ -116,7 +116,7 @@ public function testTransactionNestingLevelIsResetOnReconnect() : void $connection->executeQuery('insert into test_nesting values (33)'); $connection->rollBack(); - self::assertEquals(0, $connection->fetchColumn('select count(*) from test_nesting')); + self::assertEquals(0, $connection->fetchOne('select count(*) from test_nesting')); } public function testTransactionNestingBehaviorWithSavepoints() : void diff --git a/tests/Functional/DataAccessTest.php b/tests/Functional/DataAccessTest.php index 58c391f3a93..a871ba15c9d 100644 --- a/tests/Functional/DataAccessTest.php +++ b/tests/Functional/DataAccessTest.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Mysqli\Driver as MySQLiDriver; use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Platforms\TrimMode; @@ -16,11 +15,8 @@ use Doctrine\DBAL\Tests\FunctionalTestCase; use Doctrine\DBAL\Types\Types; use function array_change_key_case; -use function array_filter; -use function array_keys; use function count; use function date; -use function is_numeric; use function json_encode; use function sprintf; use function strtotime; @@ -62,7 +58,8 @@ public function testPrepareWithBindValue() : void $stmt->bindValue(2, 'foo'); $stmt->execute(); - $row = $stmt->fetch(FetchMode::ASSOCIATIVE); + $row = $stmt->fetchAssociative(); + self::assertIsArray($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } @@ -80,12 +77,13 @@ public function testPrepareWithBindParam() : void $stmt->bindParam(2, $paramStr); $stmt->execute(); - $row = $stmt->fetch(FetchMode::ASSOCIATIVE); + $row = $stmt->fetchAssociative(); + self::assertIsArray($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } - public function testPrepareWithFetchAll() : void + public function testPrepareWithFetchAllAssociative() : void { $paramInt = 1; $paramStr = 'foo'; @@ -98,33 +96,12 @@ public function testPrepareWithFetchAll() : void $stmt->bindParam(2, $paramStr); $stmt->execute(); - $rows = $stmt->fetchAll(FetchMode::ASSOCIATIVE); + $rows = $stmt->fetchAllAssociative(); $rows[0] = array_change_key_case($rows[0], CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $rows[0]); } - /** - * @group DBAL-228 - */ - public function testPrepareWithFetchAllBoth() : void - { - $paramInt = 1; - $paramStr = 'foo'; - - $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $stmt = $this->connection->prepare($sql); - self::assertInstanceOf(Statement::class, $stmt); - - $stmt->bindParam(1, $paramInt); - $stmt->bindParam(2, $paramStr); - $stmt->execute(); - - $rows = $stmt->fetchAll(FetchMode::MIXED); - $rows[0] = array_change_key_case($rows[0], CASE_LOWER); - self::assertEquals(['test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'], $rows[0]); - } - - public function testPrepareWithFetchColumn() : void + public function testPrepareWithFetchOne() : void { $paramInt = 1; $paramStr = 'foo'; @@ -137,7 +114,7 @@ public function testPrepareWithFetchColumn() : void $stmt->bindParam(2, $paramStr); $stmt->execute(); - $column = $stmt->fetchColumn(); + $column = $stmt->fetchOne(); self::assertEquals(1, $column); } @@ -155,8 +132,8 @@ public function testPrepareWithIterator() : void $stmt->execute(); $rows = []; - $stmt->setFetchMode(FetchMode::ASSOCIATIVE); - foreach ($stmt as $row) { + + foreach ($stmt->iterateAssociative() as $row) { $rows[] = array_change_key_case($row, CASE_LOWER); } @@ -188,16 +165,16 @@ public function testPrepareWithExecuteParams() : void self::assertInstanceOf(Statement::class, $stmt); $stmt->execute([$paramInt, $paramStr]); - $row = $stmt->fetch(FetchMode::ASSOCIATIVE); + $row = $stmt->fetchAssociative(); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } - public function testFetchAll() : void + public function testFetchAllAssociative() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $data = $this->connection->fetchAll($sql, [1, 'foo']); + $data = $this->connection->fetchAllAssociative($sql, [1, 'foo']); self::assertCount(1, $data); @@ -218,7 +195,7 @@ public function testFetchAllWithTypes() : void $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; - $data = $this->connection->fetchAll( + $data = $this->connection->fetchAllAssociative( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] @@ -250,35 +227,20 @@ public function testFetchAllWithMissingTypes() : void $this->expectException(DBALException::class); - $this->connection->fetchAll($sql, [1, $datetime]); - } - - public function testFetchBoth() : void - { - $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $row = $this->connection->executeQuery($sql, [1, 'foo'])->fetch(FetchMode::MIXED); - - self::assertNotFalse($row); - - $row = array_change_key_case($row, CASE_LOWER); - - self::assertEquals(1, $row['test_int']); - self::assertEquals('foo', $row['test_string']); - self::assertEquals(1, $row[0]); - self::assertEquals('foo', $row[1]); + $this->connection->fetchAllAssociative($sql, [1, $datetime]); } public function testFetchNoResult() : void { self::assertFalse( - $this->connection->executeQuery('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])->fetch() + $this->connection->executeQuery('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])->fetchAssociative() ); } - public function testFetchAssoc() : void + public function testFetchAssociative() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $row = $this->connection->fetchAssoc($sql, [1, 'foo']); + $row = $this->connection->fetchAssociative($sql, [1, 'foo']); self::assertNotFalse($row); @@ -294,7 +256,7 @@ public function testFetchAssocWithTypes() : void $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; - $row = $this->connection->fetchAssoc( + $row = $this->connection->fetchAssociative( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] @@ -321,13 +283,13 @@ public function testFetchAssocWithMissingTypes() : void $this->expectException(DBALException::class); - $this->connection->fetchAssoc($sql, [1, $datetime]); + $this->connection->fetchAssociative($sql, [1, $datetime]); } public function testFetchArray() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $row = $this->connection->fetchArray($sql, [1, 'foo']); + $row = $this->connection->fetchNumeric($sql, [1, 'foo']); self::assertEquals(1, $row[0]); self::assertEquals('foo', $row[1]); @@ -339,7 +301,7 @@ public function testFetchArrayWithTypes() : void $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; - $row = $this->connection->fetchArray( + $row = $this->connection->fetchNumeric( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] @@ -366,29 +328,29 @@ public function testFetchArrayWithMissingTypes() : void $this->expectException(DBALException::class); - $this->connection->fetchArray($sql, [1, $datetime]); + $this->connection->fetchNumeric($sql, [1, $datetime]); } - public function testFetchColumn() : void + public function testFetchOne() : void { $sql = 'SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $testInt = $this->connection->fetchColumn($sql, [1, 'foo']); + $testInt = $this->connection->fetchOne($sql, [1, 'foo']); self::assertEquals(1, $testInt); $sql = 'SELECT test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $testString = $this->connection->fetchColumn($sql, [1, 'foo']); + $testString = $this->connection->fetchOne($sql, [1, 'foo']); self::assertEquals('foo', $testString); } - public function testFetchColumnWithTypes() : void + public function testFetchOneWithTypes() : void { $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; - $column = $this->connection->fetchColumn( + $column = $this->connection->fetchOne( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] @@ -399,7 +361,7 @@ public function testFetchColumnWithTypes() : void self::assertStringStartsWith($datetimeString, $column); } - public function testFetchColumnWithMissingTypes() : void + public function testFetchOneWithMissingTypes() : void { if ($this->connection->getDriver() instanceof MySQLiDriver || $this->connection->getDriver() instanceof SQLSrvDriver) { @@ -412,7 +374,7 @@ public function testFetchColumnWithMissingTypes() : void $this->expectException(DBALException::class); - $this->connection->fetchColumn($sql, [1, $datetime]); + $this->connection->fetchOne($sql, [1, $datetime]); } /** @@ -427,7 +389,7 @@ public function testExecuteQueryBindDateTimeType() : void [1 => Types::DATETIME_MUTABLE] ); - self::assertEquals(1, $stmt->fetchColumn()); + self::assertEquals(1, $stmt->fetchOne()); } /** @@ -453,7 +415,7 @@ public function testExecuteUpdateBindDateTimeType() : void 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?', [1 => $datetime], [1 => Types::DATETIME_MUTABLE] - )->fetchColumn()); + )->fetchOne()); } /** @@ -466,7 +428,7 @@ public function testPrepareQueryBindValueDateTimeType() : void $stmt->bindValue(1, new DateTime('2010-01-01 10:10:10'), Types::DATETIME_MUTABLE); $stmt->execute(); - self::assertEquals(1, $stmt->fetchColumn()); + self::assertEquals(1, $stmt->fetchOne()); } /** @@ -484,7 +446,7 @@ public function testNativeArrayListSupport() : void [Connection::PARAM_INT_ARRAY] ); - $data = $stmt->fetchAll(FetchMode::NUMERIC); + $data = $stmt->fetchAllNumeric(); self::assertCount(5, $data); self::assertEquals([[100], [101], [102], [103], [104]], $data); @@ -494,7 +456,7 @@ public function testNativeArrayListSupport() : void [Connection::PARAM_STR_ARRAY] ); - $data = $stmt->fetchAll(FetchMode::NUMERIC); + $data = $stmt->fetchAllNumeric(); self::assertCount(5, $data); self::assertEquals([[100], [101], [102], [103], [104]], $data); } @@ -510,7 +472,7 @@ public function testTrimExpression(string $value, int $position, $char, string $ $this->connection->getDatabasePlatform()->getTrimExpression($value, $position, $char) . ' AS trimmed ' . 'FROM fetch_table'; - $row = $this->connection->fetchAssoc($sql); + $row = $this->connection->fetchAssociative($sql); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals($expectedResult, $row['trimmed']); @@ -586,7 +548,7 @@ public function testDateArithmetics() : void $sql .= $p->getDateSubYearsExpression('test_datetime', 6) . ' AS sub_years '; $sql .= 'FROM fetch_table'; - $row = $this->connection->fetchAssoc($sql); + $row = $this->connection->fetchAssociative($sql); $row = array_change_key_case($row, CASE_LOWER); 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'); @@ -629,7 +591,7 @@ public function testSqliteDateArithmeticWithDynamicInterval() : void $sql = 'SELECT COUNT(*) FROM fetch_table_date_math WHERE '; $sql .= $platform->getDateSubDaysExpression('test_date', 'test_days') . " < '2010-05-12'"; - $rowCount = $this->connection->fetchColumn($sql); + $rowCount = $this->connection->fetchOne($sql); self::assertEquals(1, $rowCount); } @@ -650,7 +612,7 @@ public function testLocateExpression() : void $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) . ' AS locate9 '; $sql .= 'FROM fetch_table'; - $row = $this->connection->fetchAssoc($sql); + $row = $this->connection->fetchAssociative($sql); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(2, $row['locate1']); @@ -667,7 +629,7 @@ public function testLocateExpression() : void public function testQuoteSQLInjection() : void { $sql = 'SELECT * FROM fetch_table WHERE test_string = ' . $this->connection->quote("bar' OR '1'='1"); - $rows = $this->connection->fetchAll($sql); + $rows = $this->connection->fetchAllAssociative($sql); self::assertCount(0, $rows, 'no result should be returned, otherwise SQL injection is possible'); } @@ -699,7 +661,7 @@ public function testBitComparisonExpressionSupport() : void . ' FROM fetch_table'; $stmt = $this->connection->executeQuery($sql); - $data = $stmt->fetchAll(FetchMode::ASSOCIATIVE); + $data = $stmt->fetchAllAssociative(); self::assertCount(4, $data); self::assertEquals(count($bitmap), count($data)); @@ -721,17 +683,6 @@ public function testBitComparisonExpressionSupport() : void } } - public function testSetDefaultFetchMode() : void - { - $stmt = $this->connection->query('SELECT * FROM fetch_table'); - $stmt->setFetchMode(FetchMode::NUMERIC); - - $row = array_keys($stmt->fetch()); - self::assertCount(0, array_filter($row, static function ($v) : bool { - return ! is_numeric($v); - }), 'should be no non-numerical elements in the result.'); - } - /** * @group DBAL-241 */ @@ -743,40 +694,24 @@ public function testFetchAllStyleColumn() : void $this->connection->insert('fetch_table', ['test_int' => 1, 'test_string' => 'foo']); $this->connection->insert('fetch_table', ['test_int' => 10, 'test_string' => 'foo']); - $sql = 'SELECT test_int FROM fetch_table'; - $rows = $this->connection->query($sql)->fetchAll(FetchMode::COLUMN); + $sql = 'SELECT test_int FROM fetch_table'; + $values = $this->connection->query($sql)->fetchColumn(); - self::assertEquals([1, 10], $rows); + self::assertEquals([1, 10], $values); } /** * @group DBAL-257 */ - public function testEmptyFetchColumnReturnsFalse() : void + public function testEmptyFetchOneReturnsFalse() : void { $this->connection->beginTransaction(); $this->connection->exec('DELETE FROM fetch_table'); - self::assertFalse($this->connection->fetchColumn('SELECT test_int FROM fetch_table')); - self::assertFalse($this->connection->query('SELECT test_int FROM fetch_table')->fetchColumn()); + self::assertFalse($this->connection->fetchOne('SELECT test_int FROM fetch_table')); + self::assertFalse($this->connection->query('SELECT test_int FROM fetch_table')->fetchOne()); $this->connection->rollBack(); } - /** - * @group DBAL-339 - */ - public function testSetFetchModeOnDbalStatement() : void - { - $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; - $stmt = $this->connection->executeQuery($sql, [1, 'foo']); - $stmt->setFetchMode(FetchMode::NUMERIC); - - $row = $stmt->fetch(); - - self::assertArrayHasKey(0, $row); - self::assertArrayHasKey(1, $row); - self::assertFalse($stmt->fetch()); - } - /** * @group DBAL-435 */ @@ -784,7 +719,7 @@ public function testEmptyParameters() : void { $sql = 'SELECT * FROM fetch_table WHERE test_int IN (?)'; $stmt = $this->connection->executeQuery($sql, [[]], [Connection::PARAM_INT_ARRAY]); - $rows = $stmt->fetchAll(); + $rows = $stmt->fetchAllAssociative(); self::assertEquals([], $rows); } @@ -792,10 +727,10 @@ public function testEmptyParameters() : void /** * @group DBAL-1028 */ - public function testFetchColumnNoResult() : void + public function testFetchOneNoResult() : void { self::assertFalse( - $this->connection->fetchColumn('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1]) + $this->connection->fetchOne('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1]) ); } } diff --git a/tests/Functional/Driver/OCI8/StatementTest.php b/tests/Functional/Driver/OCI8/StatementTest.php index fe49ce541bf..b87d700a116 100644 --- a/tests/Functional/Driver/OCI8/StatementTest.php +++ b/tests/Functional/Driver/OCI8/StatementTest.php @@ -33,7 +33,7 @@ public function testQueryConversion(string $query, array $params, array $expecte { self::assertEquals( $expected, - $this->connection->executeQuery($query, $params)->fetch() + $this->connection->executeQuery($query, $params)->fetchAssociative() ); } @@ -52,7 +52,7 @@ public function testStatementBindParameters(string $query, array $params, array self::assertEquals( $expected, - $stmt->fetch() + $stmt->fetchAssociative() ); } diff --git a/tests/Functional/Driver/PDOPgSql/DriverTest.php b/tests/Functional/Driver/PDOPgSql/DriverTest.php index d0209646788..37dd4af07d8 100644 --- a/tests/Functional/Driver/PDOPgSql/DriverTest.php +++ b/tests/Functional/Driver/PDOPgSql/DriverTest.php @@ -85,7 +85,7 @@ public function testConnectsWithApplicationNameParameter() : void $hash = microtime(true); // required to identify the record in the results uniquely $sql = sprintf('SELECT * FROM pg_stat_activity WHERE %d = %d', $hash, $hash); $statement = $connection->query($sql); - $records = $statement->fetchAll(); + $records = $statement->fetchAllAssociative(); foreach ($records as $record) { // The query column is named "current_query" on PostgreSQL < 9.2 diff --git a/tests/Functional/Driver/PDOPgsqlConnectionTest.php b/tests/Functional/Driver/PDOPgsqlConnectionTest.php index 2621827bd61..1c367d5bb02 100644 --- a/tests/Functional/Driver/PDOPgsqlConnectionTest.php +++ b/tests/Functional/Driver/PDOPgsqlConnectionTest.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL\Tests\Functional\Driver; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Tests\FunctionalTestCase; use function extension_loaded; @@ -44,7 +43,7 @@ public function testConnectsWithValidCharsetOption(string $charset) : void self::assertEquals( $charset, $connection->query('SHOW client_encoding') - ->fetch(FetchMode::COLUMN) + ->fetchOne() ); } diff --git a/tests/Functional/Driver/PDOSqlsrv/DriverTest.php b/tests/Functional/Driver/PDOSqlsrv/DriverTest.php index a8597ea1aaa..1b1d63f7f47 100644 --- a/tests/Functional/Driver/PDOSqlsrv/DriverTest.php +++ b/tests/Functional/Driver/PDOSqlsrv/DriverTest.php @@ -57,7 +57,7 @@ protected function getConnection(array $driverOptions) : Connection public function testConnectionOptions() : void { $connection = $this->getConnection(['APP' => 'APP_NAME']); - $result = $connection->query('SELECT APP_NAME()')->fetchColumn(); + $result = $connection->query('SELECT APP_NAME()')->fetchOne(); self::assertSame('APP_NAME', $result); } diff --git a/tests/Functional/LikeWildcardsEscapingTest.php b/tests/Functional/LikeWildcardsEscapingTest.php index 9aad98b002d..a344d8b0da5 100644 --- a/tests/Functional/LikeWildcardsEscapingTest.php +++ b/tests/Functional/LikeWildcardsEscapingTest.php @@ -23,6 +23,6 @@ public function testFetchLikeExpressionResult() : void ) ); $stmt->execute(); - self::assertTrue((bool) $stmt->fetchColumn()); + self::assertTrue((bool) $stmt->fetchOne()); } } diff --git a/tests/Functional/MasterSlaveConnectionTest.php b/tests/Functional/MasterSlaveConnectionTest.php index 255cf1575b4..e5e08b55361 100644 --- a/tests/Functional/MasterSlaveConnectionTest.php +++ b/tests/Functional/MasterSlaveConnectionTest.php @@ -89,7 +89,7 @@ public function testInheritCharsetFromMaster() : void self::assertFalse($conn->isConnectedToMaster()); - $clientCharset = $conn->fetchColumn('select @@character_set_client as c'); + $clientCharset = $conn->fetchOne('select @@character_set_client as c'); self::assertSame( $charset, @@ -114,7 +114,7 @@ public function testNoMasterOnExecuteQuery() : void $conn = $this->createMasterSlaveConnection(); $sql = 'SELECT count(*) as num FROM master_slave_table'; - $data = $conn->fetchAll($sql); + $data = $conn->fetchAllAssociative($sql); $data[0] = array_change_key_case($data[0], CASE_LOWER); self::assertEquals(1, $data[0]['num']); @@ -129,7 +129,7 @@ public function testMasterOnWriteOperation() : void self::assertTrue($conn->isConnectedToMaster()); $sql = 'SELECT count(*) as num FROM master_slave_table'; - $data = $conn->fetchAll($sql); + $data = $conn->fetchAllAssociative($sql); $data[0] = array_change_key_case($data[0], CASE_LOWER); self::assertEquals(2, $data[0]['num']); @@ -202,9 +202,8 @@ public function testQueryOnMaster() : void //Query must be executed only on Master self::assertTrue($conn->isConnectedToMaster()); - $data = $statement->fetchAll(); + $data = $statement->fetchAllAssociative(); - //Default fetchmode is FetchMode::ASSOCIATIVE self::assertArrayHasKey(0, $data); self::assertArrayHasKey('num', $data[0]); @@ -227,9 +226,8 @@ public function testQueryOnSlave() : void //Query must be executed only on Master, even when we connect to the slave self::assertTrue($conn->isConnectedToMaster()); - $data = $statement->fetchAll(); + $data = $statement->fetchAllAssociative(); - //Default fetchmode is FetchMode::ASSOCIATIVE self::assertArrayHasKey(0, $data); self::assertArrayHasKey('num', $data[0]); diff --git a/tests/Functional/ModifyLimitQueryTest.php b/tests/Functional/ModifyLimitQueryTest.php index 6900829fc3c..2bdf8ed0597 100644 --- a/tests/Functional/ModifyLimitQueryTest.php +++ b/tests/Functional/ModifyLimitQueryTest.php @@ -169,7 +169,7 @@ private function assertLimitResult(array $expectedResults, string $sql, ?int $li { $p = $this->connection->getDatabasePlatform(); $data = []; - foreach ($this->connection->fetchAll($p->modifyLimitQuery($sql, $limit, $offset)) as $row) { + foreach ($this->connection->fetchAllAssociative($p->modifyLimitQuery($sql, $limit, $offset)) as $row) { $row = array_change_key_case($row, CASE_LOWER); $data[] = $row['test_int']; } diff --git a/tests/Functional/NamedParametersTest.php b/tests/Functional/NamedParametersTest.php index 2ae35bbc2f3..4ef8be69852 100644 --- a/tests/Functional/NamedParametersTest.php +++ b/tests/Functional/NamedParametersTest.php @@ -3,7 +3,6 @@ namespace Doctrine\DBAL\Tests\Functional; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; @@ -213,7 +212,7 @@ protected function setUp() : void public function testTicket(string $query, array $params, array $types, array $expected) : void { $stmt = $this->connection->executeQuery($query, $params, $types); - $result = $stmt->fetchAll(FetchMode::ASSOCIATIVE); + $result = $stmt->fetchAllAssociative(); foreach ($result as $k => $v) { $result[$k] = array_change_key_case($v, CASE_LOWER); diff --git a/tests/Functional/Platform/DateExpressionTest.php b/tests/Functional/Platform/DateExpressionTest.php index 0f14ac4daa2..60404468595 100644 --- a/tests/Functional/Platform/DateExpressionTest.php +++ b/tests/Functional/Platform/DateExpressionTest.php @@ -26,7 +26,7 @@ public function testDifference(string $date1, string $date2, int $expected) : vo $platform = $this->connection->getDatabasePlatform(); $sql = sprintf('SELECT %s FROM date_expr_test', $platform->getDateDiffExpression('date1', 'date2')); - $diff = $this->connection->query($sql)->fetchColumn(); + $diff = $this->connection->query($sql)->fetchOne(); self::assertEquals($expected, $diff); } diff --git a/tests/Functional/Platform/DefaultExpressionTest.php b/tests/Functional/Platform/DefaultExpressionTest.php index dd735898c34..65624b0757d 100644 --- a/tests/Functional/Platform/DefaultExpressionTest.php +++ b/tests/Functional/Platform/DefaultExpressionTest.php @@ -4,7 +4,6 @@ namespace Doctrine\DBAL\Tests\Functional\Platform; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; @@ -71,7 +70,7 @@ private function assertDefaultExpression(string $type, callable $expression) : v [$actualValue, $defaultValue] = $this->connection->query( 'SELECT default_value, actual_value FROM default_expr_test' - )->fetch(FetchMode::NUMERIC); + )->fetchNumeric(); self::assertEquals($actualValue, $defaultValue); } diff --git a/tests/Functional/Platform/QuotingTest.php b/tests/Functional/Platform/QuotingTest.php index e05f5f3095e..80d15dfe330 100644 --- a/tests/Functional/Platform/QuotingTest.php +++ b/tests/Functional/Platform/QuotingTest.php @@ -16,7 +16,7 @@ public function testQuoteStringLiteral(string $string) : void $platform->quoteStringLiteral($string) ); - self::assertSame($string, $this->connection->fetchColumn($query)); + self::assertSame($string, $this->connection->fetchOne($query)); } /** diff --git a/tests/Functional/PortabilityTest.php b/tests/Functional/PortabilityTest.php index 95f945a9d31..d5b38829d33 100644 --- a/tests/Functional/PortabilityTest.php +++ b/tests/Functional/PortabilityTest.php @@ -5,7 +5,6 @@ use Doctrine\DBAL\ColumnCase; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Portability\Connection as ConnectionPortability; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; @@ -63,26 +62,19 @@ private function getPortableConnection( public function testFullFetchMode() : void { - $rows = $this->getPortableConnection()->fetchAll('SELECT * FROM portability_table'); + $rows = $this->getPortableConnection()->fetchAllAssociative('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); - $stmt->setFetchMode(FetchMode::ASSOCIATIVE); - foreach ($stmt as $row) { - $this->assertFetchResultRow($row); - } - - $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); - - while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { + while (($row = $stmt->fetchAssociative())) { $this->assertFetchResultRow($row); } $stmt = $this->getPortableConnection()->prepare('SELECT * FROM portability_table'); $stmt->execute(); - while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { + while (($row = $stmt->fetchAssociative())) { $this->assertFetchResultRow($row); } } @@ -90,24 +82,18 @@ public function testFullFetchMode() : void public function testConnFetchMode() : void { $conn = $this->getPortableConnection(); - $conn->setFetchMode(FetchMode::ASSOCIATIVE); - $rows = $conn->fetchAll('SELECT * FROM portability_table'); + $rows = $conn->fetchAllAssociative('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); $stmt = $conn->query('SELECT * FROM portability_table'); - foreach ($stmt as $row) { - $this->assertFetchResultRow($row); - } - - $stmt = $conn->query('SELECT * FROM portability_table'); - while (($row = $stmt->fetch())) { + while (($row = $stmt->fetchAssociative())) { $this->assertFetchResultRow($row); } $stmt = $conn->prepare('SELECT * FROM portability_table'); $stmt->execute(); - while (($row = $stmt->fetch())) { + while (($row = $stmt->fetchAssociative())) { $this->assertFetchResultRow($row); } } @@ -142,21 +128,21 @@ public function assertFetchResultRow(array $row) : void /** * @param mixed[] $expected * - * @dataProvider fetchAllColumnProvider + * @dataProvider fetchColumnProvider */ - public function testFetchAllColumn(string $field, array $expected) : void + public function testfetchColumn(string $field, array $expected) : void { $conn = $this->getPortableConnection(); $stmt = $conn->query('SELECT ' . $field . ' FROM portability_table'); - $column = $stmt->fetchAll(FetchMode::COLUMN); + $column = $stmt->fetchColumn(); self::assertEquals($expected, $column); } /** * @return iterable> */ - public static function fetchAllColumnProvider() : iterable + public static function fetchColumnProvider() : iterable { return [ 'int' => [ @@ -175,7 +161,7 @@ public function testFetchAllNullColumn() : void $conn = $this->getPortableConnection(); $stmt = $conn->query('SELECT Test_Null FROM portability_table'); - $column = $stmt->fetchAll(FetchMode::COLUMN); + $column = $stmt->fetchColumn(); self::assertSame([null, null], $column); } } diff --git a/tests/Functional/ResultCacheTest.php b/tests/Functional/ResultCacheTest.php index 1216b317d8d..bf558f57c61 100644 --- a/tests/Functional/ResultCacheTest.php +++ b/tests/Functional/ResultCacheTest.php @@ -5,12 +5,10 @@ use Doctrine\Common\Cache\ArrayCache; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Driver\ResultStatement; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\Logging\DebugStack; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; use function array_change_key_case; -use function array_merge; use function array_shift; use function array_values; use function is_array; @@ -57,42 +55,44 @@ protected function tearDown() : void parent::tearDown(); } - public function testCacheFetchAssoc() : void + public function testCacheFetchAssociative() : void { $this->assertCacheNonCacheSelectSameFetchModeAreEqual( $this->expectedResult, - FetchMode::ASSOCIATIVE + static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + } ); } - public function testFetchNum() : void + public function testFetchNumeric() : void { $expectedResult = []; foreach ($this->expectedResult as $v) { $expectedResult[] = array_values($v); } - $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::NUMERIC); - } - - public function testFetchBoth() : void - { - $expectedResult = []; - foreach ($this->expectedResult as $v) { - $expectedResult[] = array_merge($v, array_values($v)); - } - - $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::MIXED); + $this->assertCacheNonCacheSelectSameFetchModeAreEqual( + $expectedResult, + static function (ResultStatement $stmt) { + return $stmt->fetchNumeric(); + } + ); } - public function testFetchColumn() : void + public function testFetchOne() : void { $expectedResult = []; foreach ($this->expectedResult as $v) { $expectedResult[] = array_shift($v); } - $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::COLUMN); + $this->assertCacheNonCacheSelectSameFetchModeAreEqual( + $expectedResult, + static function (ResultStatement $stmt) { + return $stmt->fetchOne(); + } + ); } public function testMixingFetch() : void @@ -104,25 +104,25 @@ public function testMixingFetch() : void $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $data = $this->hydrateStmt($stmt, FetchMode::ASSOCIATIVE); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }); self::assertEquals($this->expectedResult, $data); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $data = $this->hydrateStmt($stmt, FetchMode::NUMERIC); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchNumeric(); + }); self::assertEquals($numExpectedResult, $data); } - public function testIteratorFetch() : void - { - self::assertStandardAndIteratorFetchAreEqual(FetchMode::MIXED); - self::assertStandardAndIteratorFetchAreEqual(FetchMode::ASSOCIATIVE); - self::assertStandardAndIteratorFetchAreEqual(FetchMode::NUMERIC); - } - - private function assertStandardAndIteratorFetchAreEqual(int $fetchMode) : void + /** + * @dataProvider fetchModeProvider + */ + public function testIteratorFetch(callable $fetchMode) : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = $this->hydrateStmt($stmt, $fetchMode); @@ -139,7 +139,7 @@ public function testDontCloseNoCache() : void $data = []; - while ($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) { + while (($row = $stmt->fetchAssociative()) !== false) { $data[] = $row; } @@ -147,7 +147,7 @@ public function testDontCloseNoCache() : void $data = []; - while ($row = $stmt->fetch(FetchMode::NUMERIC)) { + while (($row = $stmt->fetchNumeric()) !== false) { $data[] = $row; } @@ -158,12 +158,14 @@ public function testDontFinishNoCache() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $stmt->fetch(FetchMode::ASSOCIATIVE); + $stmt->fetchAssociative(); $stmt->closeCursor(); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $this->hydrateStmt($stmt, FetchMode::NUMERIC); + $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchNumeric(); + }); self::assertCount(2, $this->sqlLogger->queries); } @@ -172,13 +174,13 @@ public function testFetchAllAndFinishSavesCache() : void { $layerCache = new ArrayCache(); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'testcachekey', $layerCache)); - $stmt->fetchAll(); + $stmt->fetchAllAssociative(); $stmt->closeCursor(); self::assertCount(1, $layerCache->fetch('testcachekey')); } - public function testFetchAllColumn() : void + public function testfetchColumn() : void { $query = $this->connection->getDatabasePlatform() ->getDummySelectSQL('1'); @@ -186,18 +188,18 @@ public function testFetchAllColumn() : void $qcp = new QueryCacheProfile(0, 0, new ArrayCache()); $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp); - $stmt->fetchAll(FetchMode::COLUMN); + $stmt->fetchColumn(); $stmt->closeCursor(); $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp); - self::assertEquals([1], $stmt->fetchAll(FetchMode::COLUMN)); + self::assertEquals([1], $stmt->fetchColumn()); } /** * @param array> $expectedResult */ - private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedResult, int $fetchMode) : void + private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedResult, callable $fetchMode) : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); @@ -216,10 +218,14 @@ private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedR public function testEmptyResultCache() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }); self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit'); } @@ -227,23 +233,45 @@ public function testEmptyResultCache() : void public function testChangeCacheImpl() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }); $secondCache = new ArrayCache(); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey', $secondCache)); - $data = $this->hydrateStmt($stmt); + $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }); self::assertCount(2, $this->sqlLogger->queries, 'two hits'); self::assertCount(1, $secondCache->fetch('emptycachekey')); } + /** + * @return iterable> + */ + public static function fetchModeProvider() : iterable + { + yield 'associative' => [ + static function (ResultStatement $stmt) { + return $stmt->fetchAssociative(); + }, + ]; + + yield 'numeric' => [ + static function (ResultStatement $stmt) { + return $stmt->fetchNumeric(); + }, + ]; + } + /** * @return array */ - private function hydrateStmt(ResultStatement $stmt, int $fetchMode = FetchMode::ASSOCIATIVE) : array + private function hydrateStmt(ResultStatement $stmt, callable $fetchMode) : array { $data = []; - while ($row = $stmt->fetch($fetchMode)) { + while (($row = $fetchMode($stmt)) !== false) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } @@ -255,11 +283,11 @@ private function hydrateStmt(ResultStatement $stmt, int $fetchMode = FetchMode:: /** * @return array */ - private function hydrateStmtIterator(ResultStatement $stmt, int $fetchMode = FetchMode::ASSOCIATIVE) : array + private function hydrateStmtIterator(ResultStatement $stmt, callable $fetchMode) : array { $data = []; - $stmt->setFetchMode($fetchMode); - foreach ($stmt as $row) { + + while (($row = $fetchMode($stmt)) !== false) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } diff --git a/tests/Functional/Schema/DefaultValueTest.php b/tests/Functional/Schema/DefaultValueTest.php index 2c07c6a212e..16f1cd4f1fc 100644 --- a/tests/Functional/Schema/DefaultValueTest.php +++ b/tests/Functional/Schema/DefaultValueTest.php @@ -63,7 +63,7 @@ public function testEscapedDefaultValueCanBeIntrospected(string $name, ?string $ */ public function testEscapedDefaultValueCanBeInserted(string $name, ?string $expectedDefault) : void { - $value = $this->connection->fetchColumn( + $value = $this->connection->fetchOne( sprintf('SELECT %s FROM default_value', $name) ); diff --git a/tests/Functional/Schema/MySqlSchemaManagerTest.php b/tests/Functional/Schema/MySqlSchemaManagerTest.php index 84f42dda77c..94bce57daa5 100644 --- a/tests/Functional/Schema/MySqlSchemaManagerTest.php +++ b/tests/Functional/Schema/MySqlSchemaManagerTest.php @@ -462,7 +462,7 @@ public function testColumnDefaultsAreValid() : void 'INSERT INTO test_column_defaults_are_valid () VALUES()' ); - $row = $this->connection->fetchAssoc( + $row = $this->connection->fetchAssociative( 'SELECT *, DATEDIFF(CURRENT_TIMESTAMP(), col_datetime) as diff_seconds FROM test_column_defaults_are_valid' ); diff --git a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php index af8a0bdc37d..32a816d1570 100644 --- a/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php +++ b/tests/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -1562,7 +1562,7 @@ public function testPrimaryKeyAutoIncrement() : void $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'1\''); $query->execute(); - $lastUsedIdBeforeDelete = (int) $query->fetchColumn(); + $lastUsedIdBeforeDelete = (int) $query->fetchOne(); $this->connection->query('DELETE FROM test_pk_auto_increment'); @@ -1570,7 +1570,7 @@ public function testPrimaryKeyAutoIncrement() : void $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'2\''); $query->execute(); - $lastUsedIdAfterDelete = (int) $query->fetchColumn(); + $lastUsedIdAfterDelete = (int) $query->fetchOne(); self::assertGreaterThan($lastUsedIdBeforeDelete, $lastUsedIdAfterDelete); } diff --git a/tests/Functional/Schema/SqliteSchemaManagerTest.php b/tests/Functional/Schema/SqliteSchemaManagerTest.php index c7aedcaa9af..d6ecfc1f6b4 100644 --- a/tests/Functional/Schema/SqliteSchemaManagerTest.php +++ b/tests/Functional/Schema/SqliteSchemaManagerTest.php @@ -274,7 +274,7 @@ public function testPrimaryKeyNoAutoIncrement() : void $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = "2"'); $query->execute(); - $lastUsedIdAfterDelete = (int) $query->fetchColumn(); + $lastUsedIdAfterDelete = (int) $query->fetchOne(); // with an empty table, non autoincrement rowid is always 1 self::assertEquals(1, $lastUsedIdAfterDelete); diff --git a/tests/Functional/StatementTest.php b/tests/Functional/StatementTest.php index 59813218b59..5debfc2d1f9 100644 --- a/tests/Functional/StatementTest.php +++ b/tests/Functional/StatementTest.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver; use Doctrine\DBAL\Driver\Statement; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Tests\FunctionalTestCase; @@ -37,15 +36,15 @@ public function testStatementIsReusableAfterClosingCursor() : void $stmt->execute(); - $id = $stmt->fetchColumn(); + $id = $stmt->fetchOne(); self::assertEquals(1, $id); $stmt->closeCursor(); $stmt->execute(); - $id = $stmt->fetchColumn(); + $id = $stmt->fetchOne(); self::assertEquals(1, $id); - $id = $stmt->fetchColumn(); + $id = $stmt->fetchOne(); self::assertEquals(2, $id); } @@ -71,7 +70,7 @@ public function testReuseStatementWithLongerResults() : void $stmt->execute(); self::assertEquals([ ['param1', 'X'], - ], $stmt->fetchAll(FetchMode::NUMERIC)); + ], $stmt->fetchAllNumeric()); $row2 = [ 'param' => 'param2', @@ -83,7 +82,7 @@ public function testReuseStatementWithLongerResults() : void self::assertEquals([ ['param1', 'X'], ['param2', 'A bit longer value'], - ], $stmt->fetchAll(FetchMode::NUMERIC)); + ], $stmt->fetchAllNumeric()); } public function testFetchLongBlob() : void @@ -127,7 +126,7 @@ public function testFetchLongBlob() : void $stream = Type::getType('blob') ->convertToPHPValue( - $stmt->fetchColumn(), + $stmt->fetchOne(), $this->connection->getDatabasePlatform() ); @@ -141,14 +140,14 @@ public function testIncompletelyFetchedStatementDoesNotBlockConnection() : void $stmt1 = $this->connection->prepare('SELECT id FROM stmt_test'); $stmt1->execute(); - $stmt1->fetch(); + $stmt1->fetchAssociative(); $stmt1->execute(); // fetching only one record out of two - $stmt1->fetch(); + $stmt1->fetchAssociative(); $stmt2 = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt2->execute([1]); - self::assertEquals(1, $stmt2->fetchColumn()); + self::assertEquals(1, $stmt2->fetchOne()); } public function testReuseStatementAfterClosingCursor() : void @@ -163,13 +162,13 @@ public function testReuseStatementAfterClosingCursor() : void $stmt = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt->execute([1]); - $id = $stmt->fetchColumn(); + $id = $stmt->fetchOne(); self::assertEquals(1, $id); $stmt->closeCursor(); $stmt->execute([2]); - $id = $stmt->fetchColumn(); + $id = $stmt->fetchOne(); self::assertEquals(2, $id); } @@ -183,11 +182,11 @@ public function testReuseStatementWithParameterBoundByReference() : void $id = 1; $stmt->execute(); - self::assertEquals(1, $stmt->fetchColumn()); + self::assertEquals(1, $stmt->fetchOne()); $id = 2; $stmt->execute(); - self::assertEquals(2, $stmt->fetchColumn()); + self::assertEquals(2, $stmt->fetchOne()); } public function testReuseStatementWithReboundValue() : void @@ -199,11 +198,11 @@ public function testReuseStatementWithReboundValue() : void $stmt->bindValue(1, 1); $stmt->execute(); - self::assertEquals(1, $stmt->fetchColumn()); + self::assertEquals(1, $stmt->fetchOne()); $stmt->bindValue(1, 2); $stmt->execute(); - self::assertEquals(2, $stmt->fetchColumn()); + self::assertEquals(2, $stmt->fetchOne()); } public function testReuseStatementWithReboundParam() : void @@ -216,12 +215,12 @@ public function testReuseStatementWithReboundParam() : void $x = 1; $stmt->bindParam(1, $x); $stmt->execute(); - self::assertEquals(1, $stmt->fetchColumn()); + self::assertEquals(1, $stmt->fetchOne()); $y = 2; $stmt->bindParam(1, $y); $stmt->execute(); - self::assertEquals(2, $stmt->fetchColumn()); + self::assertEquals(2, $stmt->fetchOne()); } /** @@ -250,7 +249,7 @@ public function testCloseCursorAfterCursorEnd() : void $stmt = $this->connection->prepare('SELECT name FROM stmt_test'); $stmt->execute(); - $stmt->fetch(); + $stmt->fetchAssociative(); self::assertTrue($stmt->closeCursor()); } @@ -292,19 +291,19 @@ public static function emptyFetchProvider() : iterable return [ 'fetch' => [ static function (Statement $stmt) { - return $stmt->fetch(); + return $stmt->fetchAssociative(); }, false, ], 'fetch-column' => [ static function (Statement $stmt) { - return $stmt->fetchColumn(); + return $stmt->fetchOne(); }, false, ], 'fetch-all' => [ static function (Statement $stmt) : array { - return $stmt->fetchAll(); + return $stmt->fetchAllAssociative(); }, [], ], @@ -315,7 +314,7 @@ public function testFetchInColumnMode() : void { $platform = $this->connection->getDatabasePlatform(); $query = $platform->getDummySelectSQL(); - $result = $this->connection->executeQuery($query)->fetch(FetchMode::COLUMN); + $result = $this->connection->executeQuery($query)->fetchOne(); self::assertEquals(1, $result); } diff --git a/tests/Functional/TemporaryTableTest.php b/tests/Functional/TemporaryTableTest.php index 3764cda0f3a..73b196b198a 100644 --- a/tests/Functional/TemporaryTableTest.php +++ b/tests/Functional/TemporaryTableTest.php @@ -62,7 +62,7 @@ public function testDropTemporaryTableNotAutoCommitTransaction() : void $this->connection->rollBack(); - $rows = $this->connection->fetchAll('SELECT * FROM nontemporary'); + $rows = $this->connection->fetchAllAssociative('SELECT * FROM nontemporary'); self::assertEquals([], $rows, 'In an event of an error this result has one row, because of an implicit commit.'); } @@ -102,7 +102,7 @@ public function testCreateTemporaryTableNotAutoCommitTransaction() : void } catch (Throwable $e) { } - $rows = $this->connection->fetchAll('SELECT * FROM nontemporary'); + $rows = $this->connection->fetchAllAssociative('SELECT * FROM nontemporary'); self::assertEquals([], $rows, 'In an event of an error this result has one row, because of an implicit commit.'); } } diff --git a/tests/Functional/Ticket/DBAL202Test.php b/tests/Functional/Ticket/DBAL202Test.php index 60eaf29cacb..69d7a5ae573 100644 --- a/tests/Functional/Ticket/DBAL202Test.php +++ b/tests/Functional/Ticket/DBAL202Test.php @@ -36,7 +36,7 @@ public function testStatementRollback() : void $stmt->execute(); $this->connection->rollBack(); - self::assertEquals(0, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); + self::assertEquals(0, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchOne()); } public function testStatementCommit() : void @@ -46,6 +46,6 @@ public function testStatementCommit() : void $stmt->execute(); $this->connection->commit(); - self::assertEquals(1, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); + self::assertEquals(1, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchOne()); } } diff --git a/tests/Functional/Ticket/DBAL421Test.php b/tests/Functional/Ticket/DBAL421Test.php index ef8a4543e8a..3a15472e123 100644 --- a/tests/Functional/Ticket/DBAL421Test.php +++ b/tests/Functional/Ticket/DBAL421Test.php @@ -25,7 +25,7 @@ protected function setUp() : void public function testGuidShouldMatchPattern() : void { - $guid = $this->connection->query($this->getSelectGuidSql())->fetchColumn(); + $guid = $this->connection->query($this->getSelectGuidSql())->fetchOne(); $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'); } diff --git a/tests/Functional/Ticket/DBAL630Test.php b/tests/Functional/Ticket/DBAL630Test.php index 40ccf68b31c..d7fa2483adf 100644 --- a/tests/Functional/Ticket/DBAL630Test.php +++ b/tests/Functional/Ticket/DBAL630Test.php @@ -50,7 +50,7 @@ public function testBooleanConversionSqlLiteral() : void $id = $this->connection->lastInsertId('dbal630_id_seq'); self::assertNotEmpty($id); - $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); + $row = $this->connection->fetchAssociative('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } @@ -65,7 +65,7 @@ public function testBooleanConversionBoolParamRealPrepares() : void $id = $this->connection->lastInsertId('dbal630_id_seq'); self::assertNotEmpty($id); - $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); + $row = $this->connection->fetchAssociative('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } @@ -86,7 +86,7 @@ public function testBooleanConversionBoolParamEmulatedPrepares() : void self::assertNotEmpty($id); - $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); + $row = $this->connection->fetchAssociative('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } @@ -112,7 +112,7 @@ public function testBooleanConversionNullParamEmulatedPrepares( self::assertNotEmpty($id); - $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); + $row = $this->connection->fetchAssociative('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); self::assertSame($databaseConvertedValue, $row['bool_col']); } @@ -142,7 +142,7 @@ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInB self::assertNotEmpty($id); - $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); + $row = $this->connection->fetchAssociative('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); self::assertSame($databaseConvertedValue, $row['bool_col']); } diff --git a/tests/Functional/TypeConversionTest.php b/tests/Functional/TypeConversionTest.php index 84d48b34683..ddef32a4184 100644 --- a/tests/Functional/TypeConversionTest.php +++ b/tests/Functional/TypeConversionTest.php @@ -244,7 +244,7 @@ private function processValue(string $type, $originalValue) $sql = 'SELECT ' . $columnName . ' FROM type_conversion WHERE id = ' . self::$typeCounter; return $typeInstance->convertToPHPValue( - $this->connection->fetchColumn($sql), + $this->connection->fetchOne($sql), $this->connection->getDatabasePlatform() ); } diff --git a/tests/Functional/Types/BinaryTest.php b/tests/Functional/Types/BinaryTest.php index 04225239fe7..880194799d7 100644 --- a/tests/Functional/Types/BinaryTest.php +++ b/tests/Functional/Types/BinaryTest.php @@ -75,7 +75,7 @@ private function insert(string $id, string $value) : void */ private function select(string $id) { - $value = $this->connection->fetchColumn( + $value = $this->connection->fetchOne( 'SELECT val FROM binary_table WHERE id = ?', [$id], [ParameterType::BINARY] diff --git a/tests/Functional/WriteTest.php b/tests/Functional/WriteTest.php index 716382325fa..b1fc0490501 100644 --- a/tests/Functional/WriteTest.php +++ b/tests/Functional/WriteTest.php @@ -129,10 +129,10 @@ public function testDelete() : void $this->insertRows(); self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 2])); - self::assertCount(1, $this->connection->fetchAll('SELECT * FROM write_table')); + self::assertCount(1, $this->connection->fetchAllAssociative('SELECT * FROM write_table')); self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 1])); - self::assertCount(0, $this->connection->fetchAll('SELECT * FROM write_table')); + self::assertCount(0, $this->connection->fetchAllAssociative('SELECT * FROM write_table')); } public function testUpdate() : void @@ -175,7 +175,7 @@ public function testLastInsertIdSequence() : void })); $stmt = $this->connection->query($this->connection->getDatabasePlatform()->getSequenceNextValSQL('write_table_id_seq')); - $nextSequenceVal = $stmt->fetchColumn(); + $nextSequenceVal = $stmt->fetchOne(); $lastInsertId = $this->lastInsertId('write_table_id_seq'); @@ -205,7 +205,7 @@ public function testInsertWithKeyValueTypes() : void ['test_string' => 'datetime', 'test_int' => 'integer'] ); - $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchOne('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data); } @@ -232,7 +232,7 @@ public function testUpdateWithKeyValueTypes() : void ['test_string' => 'datetime', 'test_int' => 'integer'] ); - $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchOne('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data); } @@ -251,7 +251,7 @@ public function testDeleteWithKeyValueTypes() : void $this->connection->delete('write_table', ['test_int' => 30, 'test_string' => $val], ['test_string' => 'datetime', 'test_int' => 'integer']); - $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchOne('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertFalse($data); } @@ -307,13 +307,13 @@ public function testUpdateWhereIsNull() : void ['test_string' => 'string', 'test_int' => 'integer'] ); - $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchAllAssociative('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(1, $data); $this->connection->update('write_table', ['test_int' => 10], ['test_string' => null], ['test_string' => 'string', 'test_int' => 'integer']); - $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchAllAssociative('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(0, $data); } @@ -326,13 +326,13 @@ public function testDeleteWhereIsNull() : void ['test_string' => 'string', 'test_int' => 'integer'] ); - $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchAllAssociative('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(1, $data); $this->connection->delete('write_table', ['test_string' => null], ['test_string' => 'string']); - $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); + $data = $this->connection->fetchAllAssociative('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(0, $data); } diff --git a/tests/Portability/StatementTest.php b/tests/Portability/StatementTest.php index 49362e21ee7..ae359b76064 100644 --- a/tests/Portability/StatementTest.php +++ b/tests/Portability/StatementTest.php @@ -8,7 +8,6 @@ use Doctrine\DBAL\Portability\Statement; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use function iterator_to_array; class StatementTest extends TestCase { @@ -95,15 +94,6 @@ public function testExecute() : void self::assertTrue($this->stmt->execute($params)); } - public function testGetIterator() : void - { - $this->wrappedStmt->expects(self::exactly(3)) - ->method('fetch') - ->willReturnOnConsecutiveCalls('foo', 'bar', false); - - self::assertSame(['foo', 'bar'], iterator_to_array($this->stmt->getIterator())); - } - public function testRowCount() : void { $rowCount = 666; From 9e3c56de8c0854afceb2add17acff2c7152111d1 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 27 May 2020 09:24:49 -0700 Subject: [PATCH 8/9] Refactored ResultCacheTest for better coverage --- tests/Functional/ResultCacheTest.php | 89 +++++++++++++++++----------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/tests/Functional/ResultCacheTest.php b/tests/Functional/ResultCacheTest.php index bf558f57c61..c1cf584832b 100644 --- a/tests/Functional/ResultCacheTest.php +++ b/tests/Functional/ResultCacheTest.php @@ -102,40 +102,40 @@ public function testMixingFetch() : void $numExpectedResult[] = array_values($v); } - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { - return $stmt->fetchAssociative(); + $data = $this->hydrateViaFetchAll($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAllAssociative(); }); self::assertEquals($this->expectedResult, $data); - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { - return $stmt->fetchNumeric(); + $data = $this->hydrateViaFetchAll($stmt, static function (ResultStatement $stmt) { + return $stmt->fetchAllNumeric(); }); self::assertEquals($numExpectedResult, $data); } /** - * @dataProvider fetchModeProvider + * @dataProvider fetchProvider */ - public function testIteratorFetch(callable $fetchMode) : void + public function testFetchViaIteration(callable $fetch, callable $fetchAll) : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $data = $this->hydrateStmt($stmt, $fetchMode); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); + $data = $this->hydrateViaFetchAll($stmt, $fetchAll); - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); - $dataIterator = $this->hydrateStmtIterator($stmt, $fetchMode); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); + $dataIterator = $this->hydrateViaIteration($stmt, $fetch); self::assertEquals($data, $dataIterator); } public function testDontCloseNoCache() : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); $data = []; @@ -143,7 +143,7 @@ public function testDontCloseNoCache() : void $data[] = $row; } - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); $data = []; @@ -156,14 +156,14 @@ public function testDontCloseNoCache() : void public function testDontFinishNoCache() : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); $stmt->fetchAssociative(); $stmt->closeCursor(); - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); - $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + $this->hydrateViaIteration($stmt, static function (ResultStatement $stmt) { return $stmt->fetchNumeric(); }); @@ -173,14 +173,14 @@ public function testDontFinishNoCache() : void public function testFetchAllAndFinishSavesCache() : void { $layerCache = new ArrayCache(); - $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'testcachekey', $layerCache)); + $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(0, 'testcachekey', $layerCache)); $stmt->fetchAllAssociative(); $stmt->closeCursor(); self::assertCount(1, $layerCache->fetch('testcachekey')); } - public function testfetchColumn() : void + public function testFetchColumn() : void { $query = $this->connection->getDatabasePlatform() ->getDummySelectSQL('1'); @@ -201,29 +201,29 @@ public function testfetchColumn() : void */ private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedResult, callable $fetchMode) : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); self::assertEquals(2, $stmt->columnCount()); - $data = $this->hydrateStmt($stmt, $fetchMode); + $data = $this->hydrateViaIteration($stmt, $fetchMode); self::assertEquals($expectedResult, $data); - $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); + $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(0, 'testcachekey')); self::assertEquals(2, $stmt->columnCount()); - $data = $this->hydrateStmt($stmt, $fetchMode); + $data = $this->hydrateViaIteration($stmt, $fetchMode); self::assertEquals($expectedResult, $data); self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit'); } public function testEmptyResultCache() : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(0, 'emptycachekey')); + $this->hydrateViaIteration($stmt, static function (ResultStatement $stmt) { return $stmt->fetchAssociative(); }); - $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(0, 'emptycachekey')); + $this->hydrateViaIteration($stmt, static function (ResultStatement $stmt) { return $stmt->fetchAssociative(); }); @@ -232,14 +232,15 @@ public function testEmptyResultCache() : void public function testChangeCacheImpl() : void { - $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(0, 'emptycachekey')); + $this->hydrateViaIteration($stmt, static function (ResultStatement $stmt) { return $stmt->fetchAssociative(); }); $secondCache = new ArrayCache(); - $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey', $secondCache)); - $data = $this->hydrateStmt($stmt, static function (ResultStatement $stmt) { + + $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(0, 'emptycachekey', $secondCache)); + $this->hydrateViaIteration($stmt, static function (ResultStatement $stmt) { return $stmt->fetchAssociative(); }); @@ -250,28 +251,44 @@ public function testChangeCacheImpl() : void /** * @return iterable> */ - public static function fetchModeProvider() : iterable + public static function fetchProvider() : iterable { yield 'associative' => [ static function (ResultStatement $stmt) { return $stmt->fetchAssociative(); }, + static function (ResultStatement $stmt) { + return $stmt->fetchAllAssociative(); + }, ]; yield 'numeric' => [ static function (ResultStatement $stmt) { return $stmt->fetchNumeric(); }, + static function (ResultStatement $stmt) { + return $stmt->fetchAllNumeric(); + }, + ]; + + yield 'column' => [ + static function (ResultStatement $stmt) { + return $stmt->fetchOne(); + }, + static function (ResultStatement $stmt) { + return $stmt->fetchColumn(); + }, ]; } /** * @return array */ - private function hydrateStmt(ResultStatement $stmt, callable $fetchMode) : array + private function hydrateViaFetchAll(ResultStatement $stmt, callable $fetchAll) : array { $data = []; - while (($row = $fetchMode($stmt)) !== false) { + + foreach ($fetchAll($stmt) as $row) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } @@ -283,11 +300,11 @@ private function hydrateStmt(ResultStatement $stmt, callable $fetchMode) : array /** * @return array */ - private function hydrateStmtIterator(ResultStatement $stmt, callable $fetchMode) : array + private function hydrateViaIteration(ResultStatement $stmt, callable $fetch) : array { $data = []; - while (($row = $fetchMode($stmt)) !== false) { + while (($row = $fetch($stmt)) !== false) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } From 5df51cb367d4e1d766d4cf2830e847fb7cea3693 Mon Sep 17 00:00:00 2001 From: Sergei Morozov Date: Wed, 27 May 2020 21:17:56 -0700 Subject: [PATCH 9/9] Moved rowCount() from Statement to ResultStatement --- UPGRADE.md | 4 ++++ src/Cache/ArrayStatement.php | 9 +++++++++ src/Cache/ResultCacheStatement.php | 5 +++++ src/Driver/ResultStatement.php | 11 +++++++++++ src/Driver/Statement.php | 13 ------------- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 970d8b9a110..6048a702d30 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade to 3.0 +## BC BREAK `Statement::rowCount()` is moved. + +`Statement::rowCount()` has been moved to the `ResultStatement` interface where it belongs by definition. + ## Removed `FetchMode` and the corresponding methods 1. The `FetchMode` class and the `setFetchMode()` method of the `Connection` and `Statement` interfaces are removed. diff --git a/src/Cache/ArrayStatement.php b/src/Cache/ArrayStatement.php index f7098df0f07..8a48074bb3b 100644 --- a/src/Cache/ArrayStatement.php +++ b/src/Cache/ArrayStatement.php @@ -50,6 +50,15 @@ public function columnCount() return $this->columnCount; } + public function rowCount() : int + { + if ($this->data === null) { + return 0; + } + + return count($this->data); + } + /** * {@inheritdoc} */ diff --git a/src/Cache/ResultCacheStatement.php b/src/Cache/ResultCacheStatement.php index cf46779a143..bc41f739087 100644 --- a/src/Cache/ResultCacheStatement.php +++ b/src/Cache/ResultCacheStatement.php @@ -94,6 +94,11 @@ public function columnCount() return $this->statement->columnCount(); } + public function rowCount() : int + { + return $this->statement->rowCount(); + } + /** * {@inheritdoc} */ diff --git a/src/Driver/ResultStatement.php b/src/Driver/ResultStatement.php index 8fe6be076b4..3a065ec6318 100644 --- a/src/Driver/ResultStatement.php +++ b/src/Driver/ResultStatement.php @@ -25,6 +25,17 @@ public function closeCursor(); */ public function columnCount(); + /** + * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + */ + public function rowCount() : int; + /** * Returns the next row of a result set as a numeric array or FALSE if there are no more rows. * diff --git a/src/Driver/Statement.php b/src/Driver/Statement.php index 4fb7865e28f..2bd1e879470 100644 --- a/src/Driver/Statement.php +++ b/src/Driver/Statement.php @@ -72,17 +72,4 @@ public function bindParam($column, &$variable, $type = ParameterType::STRING, $l * @return bool TRUE on success or FALSE on failure. */ public function execute($params = null); - - /** - * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement - * executed by the corresponding object. - * - * If the last SQL statement executed by the associated Statement object was a SELECT statement, - * some databases may return the number of rows returned by that statement. However, - * this behaviour is not guaranteed for all databases and should not be - * relied on for portable applications. - * - * @return int The number of rows. - */ - public function rowCount() : int; }