Unverified Commit 2b63c38c authored by Sergei Morozov's avatar Sergei Morozov

Merge branch '3.0.x'

parents ece6cd6b 66b1f3d2
......@@ -70,15 +70,14 @@ install:
$destination = "c:\tools\php\ext\php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip"
Invoke-WebRequest $source -OutFile $destination
7z x -y php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip > $null
$DLLVersion = (Invoke-WebRequest "https://pecl.php.net/rest/r/xdebug/stable.txt").Content
$source = "https://xdebug.org/files/php_xdebug-$($DLLVersion)-$($env:php)-vc15-nts-x86_64.dll"
$destination = "c:\tools\php\ext\php_xdebug.dll"
Invoke-WebRequest $source -OutFile $destination
$DLLVersion = (Invoke-WebRequest "https://pecl.php.net/rest/r/pcov/stable.txt").Content
Invoke-WebRequest https://windows.php.net/downloads/pecl/releases/pcov/$($DLLVersion)/php_pcov-$($DLLVersion)-7.4-nts-vc15-$($env:platform).zip -OutFile pcov.zip
7z x -y pcov.zip > $null
Remove-Item c:\tools\php\* -include .zip
cd c:\tools\php
Add-Content php.ini "`nextension=php_sqlsrv.dll"
Add-Content php.ini "`nextension=php_pdo_sqlsrv.dll"
Add-Content php.ini "`nzend_extension=php_xdebug.dll"
Add-Content php.ini "`nextension=php_pcov.dll"
Add-Content php.ini "`n"
# download Composer
......@@ -119,8 +118,12 @@ test_script:
$env:phpunit_config = "ci\appveyor\$($env:db).$($env:driver).appveyor.xml"
}
vendor\bin\phpunit -c $($env:phpunit_config)
vendor\bin\phpunit -c $($env:phpunit_config) --coverage-clover clover.xml
if ($LastExitCode -ne 0) {
$host.SetShouldExit($LastExitCode)
}
after_test:
- appveyor DownloadFile https://codecov.io/bash -FileName codecov.sh
- bash codecov.sh -f clover.xml
coverage_clover: clover.xml
json_path: /tmp/coveralls-upload.json
......@@ -8,12 +8,7 @@ cache:
before_install:
- phpenv config-rm xdebug.ini || true
- |
if [ "x$COVERAGE" == "xyes" ]; then
pecl install pcov-1.0.6
wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.2.0/php-coveralls.phar --output-document="${HOME}/bin/coveralls"
chmod +x ${HOME}/bin/coveralls
fi
- pecl install pcov
before_script:
- |
......@@ -30,80 +25,72 @@ install:
- travis_retry composer -n install --prefer-dist $COMPOSER_FLAGS
script:
- |
if [ "x$COVERAGE" == "xyes" ]; then
./vendor/bin/phpunit --configuration ci/travis/$DB.travis.xml --coverage-clover clover.xml
else
./vendor/bin/phpunit --configuration ci/travis/$DB.travis.xml
fi
- ./vendor/bin/phpunit --configuration ci/travis/$DB.travis.xml --coverage-clover clover.xml
after_script:
- |
if [ "x$COVERAGE" == "xyes" ]; then
travis_retry coveralls -v
fi
after_success:
- bash <(curl -s https://codecov.io/bash)
jobs:
include:
- stage: Smoke Testing
php: 7.4
env: DB=sqlite COVERAGE=yes
env: DB=sqlite
- stage: Test
php: 7.3
env: DB=mysql.docker IMAGE=mysql:5.7 COVERAGE=yes
env: DB=mysql.docker IMAGE=mysql:5.7
- stage: Test
php: 7.3
env: DB=mysql.docker IMAGE=mysql:8.0 COVERAGE=yes
env: DB=mysql.docker IMAGE=mysql:8.0
- stage: Test
php: 7.3
env: DB=mysqli.docker IMAGE=mysql:5.7 COVERAGE=yes
env: DB=mysqli.docker IMAGE=mysql:5.7
- stage: Test
php: 7.3
env: DB=mysqli.docker IMAGE=mysql:8.0 COVERAGE=yes
env: DB=mysqli.docker IMAGE=mysql:8.0
- stage: Test
php: 7.3
env: DB=mariadb.docker IMAGE=mariadb:10.0 COVERAGE=yes
env: DB=mariadb.docker IMAGE=mariadb:10.0
- stage: Test
php: 7.3
env: DB=mariadb.docker IMAGE=mariadb:10.1 COVERAGE=yes
env: DB=mariadb.docker IMAGE=mariadb:10.1
- stage: Test
php: 7.3
env: DB=mariadb.docker IMAGE=mariadb:10.2 COVERAGE=yes
env: DB=mariadb.docker IMAGE=mariadb:10.2
- stage: Test
php: 7.3
env: DB=mariadb.docker IMAGE=mariadb:10.3 COVERAGE=yes
env: DB=mariadb.docker IMAGE=mariadb:10.3
- stage: Test
php: 7.3
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.0 COVERAGE=yes
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.0
- stage: Test
php: 7.3
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.1 COVERAGE=yes
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.1
- stage: Test
php: 7.3
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.2 COVERAGE=yes
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.2
- stage: Test
php: 7.3
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.3 COVERAGE=yes
env: DB=mariadb.mysqli.docker IMAGE=mariadb:10.3
- stage: Test
php: 7.3
env: DB=pgsql POSTGRESQL_VERSION=9.4 COVERAGE=yes
env: DB=pgsql POSTGRESQL_VERSION=9.4
addons:
postgresql: "9.4"
- stage: Test
php: 7.3
env: DB=pgsql POSTGRESQL_VERSION=9.5 COVERAGE=yes
env: DB=pgsql POSTGRESQL_VERSION=9.5
addons:
postgresql: "9.5"
- stage: Test
php: 7.3
env: DB=pgsql POSTGRESQL_VERSION=9.6 COVERAGE=yes
env: DB=pgsql POSTGRESQL_VERSION=9.6
addons:
postgresql: "9.6"
- stage: Test
php: 7.3
env: DB=pgsql POSTGRESQL_VERSION=10.0 COVERAGE=yes
env: DB=pgsql POSTGRESQL_VERSION=10.0
sudo: required
addons:
postgresql: "10"
......@@ -111,13 +98,13 @@ jobs:
- bash ./ci/travis/install-postgres-10.sh
- stage: Test
php: 7.3
env: DB=pgsql POSTGRESQL_VERSION=11.0 COVERAGE=yes
env: DB=pgsql POSTGRESQL_VERSION=11.0
sudo: required
before_script:
- bash ./ci/travis/install-postgres-11.sh
- stage: Test
php: 7.3
env: DB=sqlsrv COVERAGE=yes
env: DB=sqlsrv
sudo: required
before_script:
- bash ./ci/travis/install-sqlsrv-dependencies.sh
......@@ -125,7 +112,7 @@ jobs:
- bash ./ci/travis/install-mssql.sh
- stage: Test
php: 7.3
env: DB=pdo_sqlsrv COVERAGE=yes
env: DB=pdo_sqlsrv
sudo: required
before_script:
- bash ./ci/travis/install-sqlsrv-dependencies.sh
......@@ -133,7 +120,7 @@ jobs:
- bash ./ci/travis/install-mssql.sh
- stage: Test
php: 7.3
env: DB=ibm_db2 COVERAGE=yes
env: DB=ibm_db2
sudo: required
before_script:
- bash ./ci/travis/install-db2.sh
......
......@@ -4,7 +4,7 @@
|:----------------:|:----------:|
| [![Build status][Master image]][Master] | [![Build status][2.10 image]][2.10] |
| [![Build Status][ContinuousPHP image]][ContinuousPHP] | [![Build Status][ContinuousPHP 2.10 image]][ContinuousPHP] |
| [![Code Coverage][Coverage image]][Coveralls Master] | [![Code Coverage][Coverage 2.10 image]][Coveralls 2.10] |
| [![Code Coverage][Coverage image]][CodeCov Master] | [![Code Coverage][Coverage 2.10 image]][CodeCov 2.10] |
| [![AppVeyor][AppVeyor master image]][AppVeyor master] | [![AppVeyor][AppVeyor 2.10 image]][AppVeyor 2.10] |
Powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction.
......@@ -16,18 +16,18 @@ Powerful database abstraction layer with many features for database schema intro
* [Issue Tracker](https://github.com/doctrine/dbal/issues)
[Master image]: https://img.shields.io/travis/doctrine/dbal/master.svg?style=flat-square
[Coverage image]: https://coveralls.io/repos/github/doctrine/dbal/badge.svg?branch=master
[Coverage image]: https://codecov.io/gh/doctrine/dbal/branch/master/graph/badge.svg
[ContinuousPHP image]: https://img.shields.io/continuousphp/git-hub/doctrine/dbal/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/dbal
[Coveralls Master]: https://coveralls.io/github/doctrine/dbal?branch=master
[CodeCov Master]: https://codecov.io/gh/doctrine/dbal/branch/master
[AppVeyor master]: https://ci.appveyor.com/project/doctrine/dbal/branch/master
[AppVeyor master image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/master?svg=true
[ContinuousPHP]: https://continuousphp.com/git-hub/doctrine/dbal
[2.10 image]: https://img.shields.io/travis/doctrine/dbal/2.10.x.svg?style=flat-square
[Coverage 2.10 image]: https://coveralls.io/repos/github/doctrine/dbal/badge.svg?branch=2.10.x
[Coverage 2.10 image]: https://codecov.io/gh/doctrine/dbal/branch/2.10.x/graph/badge.svg
[ContinuousPHP 2.10 image]: https://img.shields.io/continuousphp/git-hub/doctrine/dbal/2.10.x.svg?style=flat-square
[2.10]: https://github.com/doctrine/dbal/tree/2.10.x
[Coveralls 2.10]: https://coveralls.io/github/doctrine/dbal?branch=2.10.x
[CodeCov 2.10]: https://codecov.io/gh/doctrine/dbal/branch/2.10.x
[AppVeyor 2.10]: https://ci.appveyor.com/project/doctrine/dbal/branch/2.10.x
[AppVeyor 2.10 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/2.10.x?svg=true
......@@ -260,6 +260,17 @@ The Doctrine\DBAL\Version class is no longer available: please refrain from chec
# Upgrade to 3.0
## BC BREAK changes in fetching statement results
1. The `Statement` interface no longer extends `ResultStatement`.
2. The `ResultStatement` interface has been renamed to `Result`.
3. Instead of returning `bool`, `Statement::execute()` now returns a `Result` that should be used for fetching the result data and metadata.
4. The functionality previously available via `Statement::closeCursor()` is now available via `Result::free()`. The behavior of fetching data from a freed result is no longer portable. In this case, some drivers will return `false` while others may throw an exception.
Additional related changes:
1. The `ArrayStatement` and `ResultCacheStatement` classes from the `Cache` package have been renamed to `ArrayResult` and `CachingResult` respectively and marked `@internal`.
## BC BREAK `Statement::rowCount()` is moved.
`Statement::rowCount()` has been moved to the `ResultStatement` interface where it belongs by definition.
......@@ -424,14 +435,23 @@ Please use other database client applications for import, e.g.:
# Upgrade to 2.11
## Deprecated `ArrayStatement` and `ResultCacheStatement` classes.
The `ArrayStatement` and `ResultCacheStatement` classes are deprecated. In a future major release they will be renamed and marked internal as implementation details of the caching layer.
## Deprecated `ResultStatement` interface
1. The `ResultStatement` interface is deprecated. Use the `Driver\Result` and `Abstraction\Result` interfaces instead.
2. `ResultStatement::closeCursor()` is deprecated in favor of `Result::free()`.
## 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()`.
2. The `Statement::fetch()` method is deprecated in favor of `Result::fetchNumeric()`, `::fetchAssociative()` and `::fetchOne()`.
3. The `Statement::fetchAll()` method is deprecated in favor of `Result::fetchAllNumeric()`, `::fetchAllAssociative()` and `::fetchFirstColumn()`.
4. The `Statement::fetchColumn()` method is deprecated in favor of `Result::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()`.
6. The `StatementIterator` class and the usage of a `Statement` object as `Traversable` is deprecated in favor of `Result::iterateNumeric()`, `::iterateAssociative()` and `::iterateColumn()`.
7. Fetching data in mixed mode (`FetchMode::MIXED`) is deprecated.
## Deprecated `Connection::project()`
......
......@@ -4,7 +4,7 @@ declare(strict_types=1);
use Doctrine\DBAL\DriverManager;
(static function () : void {
(static function (): void {
// workaround for https://bugs.php.net/bug.php?id=77120
DriverManager::getConnection([
'driver' => 'oci8',
......
......@@ -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": "443135f1aaa5ecf64132fd13d99efb6c",
"content-hash": "c61d6544a7d6c20b068a7c29c7e006d1",
"packages": [
{
"name": "doctrine/cache",
......@@ -462,16 +462,16 @@
},
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
"version": "v0.5.0",
"version": "v0.6.2",
"source": {
"type": "git",
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
"reference": "e749410375ff6fb7a040a68878c656c2e610b132"
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132",
"reference": "e749410375ff6fb7a040a68878c656c2e610b132",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/8001af8eb107fbfcedc31a8b51e20b07d85b457a",
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a",
"shasum": ""
},
"require": {
......@@ -524,27 +524,27 @@
"stylecheck",
"tests"
],
"time": "2018-10-26T13:21:45+00:00"
"time": "2020-01-29T20:22:20+00:00"
},
{
"name": "doctrine/coding-standard",
"version": "7.0.2",
"version": "8.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/coding-standard.git",
"reference": "d8a60ec4da68025c42795b714f66e277dd3e11de"
"reference": "742200e29fb8ffd58ba9abec8a9ec33db0884677"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/coding-standard/zipball/d8a60ec4da68025c42795b714f66e277dd3e11de",
"reference": "d8a60ec4da68025c42795b714f66e277dd3e11de",
"url": "https://api.github.com/repos/doctrine/coding-standard/zipball/742200e29fb8ffd58ba9abec8a9ec33db0884677",
"reference": "742200e29fb8ffd58ba9abec8a9ec33db0884677",
"shasum": ""
},
"require": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
"php": "^7.2",
"slevomat/coding-standard": "^6.0",
"squizlabs/php_codesniffer": "^3.5.3"
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
"php": "^7.2 || ^8.0",
"slevomat/coding-standard": "^6.3.8",
"squizlabs/php_codesniffer": "^3.5.5"
},
"type": "phpcodesniffer-standard",
"extra": {
......@@ -552,11 +552,6 @@
"dev-master": "7.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Sniffs\\": "lib/Doctrine/Sniffs"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
......@@ -585,7 +580,7 @@
"standard",
"style"
],
"time": "2019-12-11T07:59:21+00:00"
"time": "2020-06-02T17:58:43+00:00"
},
{
"name": "doctrine/instantiator",
......
......@@ -35,15 +35,13 @@ the default cache instance:
new QueryCacheProfile(0, "some key", $cache);
In order for the data to actually be cached its necessary to ensure that the entire
result set is read (the easiest way to ensure this is to use ``fetchAll``) and the statement
object is closed:
result set is read (the easiest way to ensure this is to use one of the ``fetchAll*()`` methods):
::
<?php
$stmt = $conn->executeCacheQuery($query, $params, $types, new QueryCacheProfile(0, "some key"));
$data = $stmt->fetchAllAssociative();
$stmt->closeCursor(); // at this point the result is cached
.. warning::
......
......@@ -21,7 +21,9 @@
<exclude name="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming"/>
<exclude name="SlevomatCodingStandard.Classes.DisallowLateStaticBindingForConstants.DisallowedLateStaticBindingForConstant"/>
<exclude name="SlevomatCodingStandard.ControlStructures.ControlStructureSpacing.IncorrectLinesCountAfterLastControlStructure"/>
<exclude name="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceEqualOperator"/>
<exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
<!-- https://github.com/slevomat/coding-standard/issues/867 -->
<exclude name="SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing.IncorrectLinesCountAfterLastControlStructure"/>
<!-- See https://github.com/squizlabs/PHP_CodeSniffer/issues/2937 -->
......@@ -97,7 +99,8 @@
<!-- some statement classes close cursor using an empty while-loop -->
<rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedWhile">
<exclude-pattern>src/Driver/SQLSrv/SQLSrvStatement.php</exclude-pattern>
<exclude-pattern>src/Driver/SQLSrv/Result.php</exclude-pattern>
<exclude-pattern>tests/Functional/ResultCacheTest.php</exclude-pattern>
</rule>
<!-- see https://github.com/doctrine/dbal/issues/3377 -->
......@@ -114,6 +117,6 @@
<!-- The SQLSRV_* functions are defined in the upper case by the sqlsrv extension and violate the standard
see https://docs.microsoft.com/en-us/sql/connect/php/constants-microsoft-drivers-for-php-for-sql-server -->
<rule ref="Squiz.PHP.LowercasePHPFunctions">
<exclude-pattern>lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php</exclude-pattern>
<exclude-pattern>src/Driver/SQLSrv/SQLSrvStatement.php</exclude-pattern>
</rule>
</ruleset>
......@@ -32,7 +32,9 @@ parameters:
path: %currentWorkingDirectory%/tests/Functional/DataAccessTest.php
# https://github.com/JetBrains/phpstorm-stubs/pull/766
- '~^Method Doctrine\\DBAL\\Driver\\Mysqli\\MysqliStatement::fetch\(\) never returns null so it can be removed from the return typehint\.$~'
-
message: '~^Strict comparison using === between true and null will always evaluate to false\.$~'
path: %currentWorkingDirectory%/src/Driver/Mysqli/Result.php
# The ReflectionException in the case when the class does not exist is acceptable and does not need to be handled
- '~^Parameter #1 \$argument of class ReflectionClass constructor expects class-string<T of object>\|T of object, string given\.$~'
......
......@@ -2,15 +2,17 @@
declare(strict_types=1);
namespace Doctrine\DBAL;
namespace Doctrine\DBAL\Abstraction;
use Doctrine\DBAL\Driver\ResultStatement as DriverResultStatement;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\Result as DriverResult;
use Traversable;
/**
* DBAL-level ResultStatement interface.
* Abstraction-level statement execution result. Provides additional methods on top
* of the driver-level interface.
*/
interface ResultStatement extends DriverResultStatement
interface Result extends DriverResult
{
/**
* Returns an iterator over the result set rows represented as numeric arrays.
......@@ -19,7 +21,7 @@ interface ResultStatement extends DriverResultStatement
*
* @throws DBALException
*/
public function iterateNumeric() : Traversable;
public function iterateNumeric(): Traversable;
/**
* Returns an iterator over the result set rows represented as associative arrays.
......@@ -28,7 +30,7 @@ interface ResultStatement extends DriverResultStatement
*
* @throws DBALException
*/
public function iterateAssociative() : Traversable;
public function iterateAssociative(): Traversable;
/**
* Returns an iterator over the values of the first column of the result set.
......@@ -37,5 +39,5 @@ interface ResultStatement extends DriverResultStatement
*
* @throws DBALException
*/
public function iterateColumn() : Traversable;
public function iterateColumn(): Traversable;
}
......@@ -5,12 +5,16 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Cache;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result;
use function array_values;
use function count;
use function reset;
final class ArrayStatement implements ResultStatement
/**
* @internal The class is internal to the caching layer implementation.
*/
final class ArrayResult implements Result
{
/** @var mixed[] */
private $data;
......@@ -34,21 +38,6 @@ final class ArrayStatement implements ResultStatement
$this->columnCount = count($data[0]);
}
public function closeCursor() : void
{
$this->data = [];
}
public function columnCount() : int
{
return $this->columnCount;
}
public function rowCount() : int
{
return count($this->data);
}
/**
* {@inheritdoc}
*/
......@@ -88,7 +77,7 @@ final class ArrayStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchAllNumeric() : array
public function fetchAllNumeric(): array
{
return FetchUtils::fetchAllNumeric($this);
}
......@@ -96,7 +85,7 @@ final class ArrayStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchAllAssociative() : array
public function fetchAllAssociative(): array
{
return FetchUtils::fetchAllAssociative($this);
}
......@@ -104,9 +93,28 @@ final class ArrayStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchColumn() : array
public function fetchFirstColumn(): array
{
return FetchUtils::fetchColumn($this);
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
if ($this->data === null) {
return 0;
}
return count($this->data);
}
public function columnCount(): int
{
return $this->columnCount;
}
public function free(): void
{
$this->data = [];
}
/**
......
......@@ -7,13 +7,12 @@ namespace Doctrine\DBAL\Cache;
use Doctrine\Common\Cache\Cache;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result;
use function array_map;
use function array_values;
/**
* Cache statement for SQL results.
*
* A result is saved in multiple cache keys, there is the originally specified
* cache key which is just pointing to result rows by key. The following things
* have to be ensured:
......@@ -23,11 +22,13 @@ use function array_values;
*
* 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.
*
* @internal The class is internal to the caching layer implementation.
*/
final class ResultCacheStatement implements ResultStatement
final class CachingResult implements Result
{
/** @var Cache */
private $resultCache;
private $cache;
/** @var string */
private $cacheKey;
......@@ -38,55 +39,19 @@ final class ResultCacheStatement implements ResultStatement
/** @var int */
private $lifetime;
/** @var ResultStatement */
private $statement;
/**
* Did we reach the end of the statement?
*
* @var bool
*/
private $emptied = false;
/** @var Result */
private $result;
/** @var array<int,array<string,mixed>> */
/** @var array<int,array<string,mixed>>|null */
private $data;
public function __construct(ResultStatement $stmt, Cache $resultCache, string $cacheKey, string $realKey, int $lifetime)
{
$this->statement = $stmt;
$this->resultCache = $resultCache;
$this->cacheKey = $cacheKey;
$this->realKey = $realKey;
$this->lifetime = $lifetime;
}
public function closeCursor() : void
{
$this->statement->closeCursor();
if (! $this->emptied || $this->data === null) {
return;
}
$data = $this->resultCache->fetch($this->cacheKey);
if ($data === false) {
$data = [];
}
$data[$this->realKey] = $this->data;
$this->resultCache->save($this->cacheKey, $data, $this->lifetime);
unset($this->data);
}
public function columnCount() : int
{
return $this->statement->columnCount();
}
public function rowCount() : int
public function __construct(Result $result, Cache $cache, string $cacheKey, string $realKey, int $lifetime)
{
return $this->statement->rowCount();
$this->result = $result;
$this->cache = $cache;
$this->cacheKey = $cacheKey;
$this->realKey = $realKey;
$this->lifetime = $lifetime;
}
/**
......@@ -122,10 +87,10 @@ final class ResultCacheStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchAllNumeric() : array
public function fetchAllNumeric(): array
{
$this->store(
$this->statement->fetchAllAssociative()
$this->result->fetchAllAssociative()
);
return array_map('array_values', $this->data);
......@@ -134,10 +99,10 @@ final class ResultCacheStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchAllAssociative() : array
public function fetchAllAssociative(): array
{
$this->store(
$this->statement->fetchAllAssociative()
$this->result->fetchAllAssociative()
);
return $this->data;
......@@ -146,9 +111,24 @@ final class ResultCacheStatement implements ResultStatement
/**
* {@inheritdoc}
*/
public function fetchColumn() : array
public function fetchFirstColumn(): array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
return $this->result->rowCount();
}
public function columnCount(): int
{
return FetchUtils::fetchColumn($this);
return $this->result->columnCount();
}
public function free(): void
{
$this->data = null;
}
/**
......@@ -162,7 +142,7 @@ final class ResultCacheStatement implements ResultStatement
$this->data = [];
}
$row = $this->statement->fetchAssociative();
$row = $this->result->fetchAssociative();
if ($row !== false) {
$this->data[] = $row;
......@@ -170,7 +150,7 @@ final class ResultCacheStatement implements ResultStatement
return $row;
}
$this->emptied = true;
$this->saveToCache();
return false;
}
......@@ -178,9 +158,27 @@ final class ResultCacheStatement implements ResultStatement
/**
* @param array<int,array<string,mixed>> $data
*/
private function store(array $data) : void
private function store(array $data): void
{
$this->data = $data;
$this->emptied = true;
$this->data = $data;
$this->saveToCache();
}
private function saveToCache(): void
{
if ($this->data === null) {
return;
}
$data = $this->cache->fetch($this->cacheKey);
if ($data === false) {
$data = [];
}
$data[$this->realKey] = $this->data;
$this->cache->save($this->cacheKey, $data, $this->lifetime);
}
}
......@@ -11,7 +11,7 @@ use Doctrine\DBAL\Cache\CacheException;
*/
final class NoCacheKey extends CacheException
{
public static function new() : self
public static function new(): self
{
return new self('No cache key was set.');
}
......
......@@ -11,7 +11,7 @@ use Doctrine\DBAL\Cache\CacheException;
*/
final class NoResultDriverConfigured extends CacheException
{
public static function new() : self
public static function new(): self
{
return new self('Trying to cache a query but no result driver is configured.');
}
......
......@@ -6,6 +6,7 @@ namespace Doctrine\DBAL\Cache;
use Doctrine\Common\Cache\Cache;
use Doctrine\DBAL\Cache\Exception\NoCacheKey;
use function hash;
use function serialize;
use function sha1;
......@@ -33,12 +34,12 @@ class QueryCacheProfile
$this->resultCacheDriver = $resultCache;
}
public function getResultCacheDriver() : ?Cache
public function getResultCacheDriver(): ?Cache
{
return $this->resultCacheDriver;
}
public function getLifetime() : int
public function getLifetime(): int
{
return $this->lifetime;
}
......@@ -46,7 +47,7 @@ class QueryCacheProfile
/**
* @throws CacheException
*/
public function getCacheKey() : string
public function getCacheKey(): string
{
if ($this->cacheKey === null) {
throw NoCacheKey::new();
......@@ -64,7 +65,7 @@ class QueryCacheProfile
*
* @return string[]
*/
public function generateCacheKeys(string $query, array $params, array $types, array $connectionParams = []) : array
public function generateCacheKeys(string $query, array $params, array $types, array $connectionParams = []): array
{
$realCacheKey = 'query=' . $query .
'&params=' . serialize($params) .
......@@ -81,17 +82,17 @@ class QueryCacheProfile
return [$cacheKey, $realCacheKey];
}
public function setResultCacheDriver(Cache $cache) : self
public function setResultCacheDriver(Cache $cache): self
{
return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache);
}
public function setCacheKey(?string $cacheKey) : self
public function setCacheKey(?string $cacheKey): self
{
return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCacheDriver);
}
public function setLifetime(int $lifetime) : self
public function setLifetime(int $lifetime): self
{
return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCacheDriver);
}
......
......@@ -27,7 +27,7 @@ class Configuration
/**
* Sets the SQL logger to use.
*/
public function setSQLLogger(?SQLLogger $logger) : void
public function setSQLLogger(?SQLLogger $logger): void
{
$this->_attributes['sqlLogger'] = $logger;
}
......@@ -35,7 +35,7 @@ class Configuration
/**
* Gets the SQL logger that is used.
*/
public function getSQLLogger() : SQLLogger
public function getSQLLogger(): SQLLogger
{
return $this->_attributes['sqlLogger'] ?? $this->_attributes['sqlLogger'] = new NullLogger();
}
......@@ -43,7 +43,7 @@ class Configuration
/**
* Gets the cache driver implementation that is used for query result caching.
*/
public function getResultCacheImpl() : ?Cache
public function getResultCacheImpl(): ?Cache
{
return $this->_attributes['resultCacheImpl'] ?? null;
}
......@@ -51,7 +51,7 @@ class Configuration
/**
* Sets the cache driver implementation that is used for query result caching.
*/
public function setResultCacheImpl(Cache $cacheImpl) : void
public function setResultCacheImpl(Cache $cacheImpl): void
{
$this->_attributes['resultCacheImpl'] = $cacheImpl;
}
......@@ -59,7 +59,7 @@ class Configuration
/**
* Sets the callable to use to filter schema assets.
*/
public function setSchemaAssetsFilter(?callable $callable = null) : ?callable
public function setSchemaAssetsFilter(?callable $callable = null): ?callable
{
$this->_attributes['filterSchemaAssetsExpression'] = null;
......@@ -69,7 +69,7 @@ class Configuration
/**
* Returns the callable to use to filter schema assets.
*/
public function getSchemaAssetsFilter() : ?callable
public function getSchemaAssetsFilter(): ?callable
{
return $this->_attributes['filterSchemaAssetsExpressionCallable'] ?? null;
}
......@@ -85,7 +85,7 @@ class Configuration
*
* @param bool $autoCommit True to enable auto-commit mode; false to disable it.
*/
public function setAutoCommit(bool $autoCommit) : void
public function setAutoCommit(bool $autoCommit): void
{
$this->_attributes['autoCommit'] = $autoCommit;
}
......@@ -97,7 +97,7 @@ class Configuration
*
* @return bool True if auto-commit mode is enabled by default for connections, false otherwise.
*/
public function getAutoCommit() : bool
public function getAutoCommit(): bool
{
return $this->_attributes['autoCommit'] ?? true;
}
......
This diff is collapsed.
......@@ -9,11 +9,12 @@ use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use InvalidArgumentException;
use function array_rand;
use function assert;
use function count;
......@@ -121,12 +122,12 @@ class MasterSlaveConnection extends Connection
/**
* Checks if the connection is currently towards the master or not.
*/
public function isConnectedToMaster() : bool
public function isConnectedToMaster(): bool
{
return $this->_conn !== null && $this->_conn === $this->connections['master'];
}
public function connect(?string $connectionName = null) : void
public function connect(?string $connectionName = null): void
{
$requestedConnectionChange = ($connectionName !== null);
$connectionName = $connectionName ?? 'slave';
......@@ -181,7 +182,7 @@ class MasterSlaveConnection extends Connection
/**
* Connects to a specific connection.
*/
protected function connectTo(string $connectionName) : DriverConnection
protected function connectTo(string $connectionName): DriverConnection
{
$params = $this->getParams();
......@@ -200,7 +201,7 @@ class MasterSlaveConnection extends Connection
*
* @return array<string, mixed>
*/
protected function chooseConnectionConfiguration(string $connectionName, array $params) : array
protected function chooseConnectionConfiguration(string $connectionName, array $params): array
{
if ($connectionName === 'master') {
return $params['master'];
......@@ -218,28 +219,28 @@ class MasterSlaveConnection extends Connection
/**
* {@inheritDoc}
*/
public function executeUpdate(string $query, array $params = [], array $types = []) : int
public function executeUpdate(string $query, array $params = [], array $types = []): int
{
$this->connect('master');
return parent::executeUpdate($query, $params, $types);
}
public function beginTransaction() : void
public function beginTransaction(): void
{
$this->connect('master');
parent::beginTransaction();
}
public function commit() : void
public function commit(): void
{
$this->connect('master');
parent::commit();
}
public function rollBack() : void
public function rollBack(): void
{
$this->connect('master');
......@@ -249,14 +250,14 @@ class MasterSlaveConnection extends Connection
/**
* {@inheritDoc}
*/
public function delete(string $table, array $identifier, array $types = []) : int
public function delete(string $table, array $identifier, array $types = []): int
{
$this->connect('master');
return parent::delete($table, $identifier, $types);
}
public function close() : void
public function close(): void
{
unset($this->connections['master'], $this->connections['slave']);
......@@ -269,7 +270,7 @@ class MasterSlaveConnection extends Connection
/**
* {@inheritDoc}
*/
public function update(string $table, array $data, array $identifier, array $types = []) : int
public function update(string $table, array $data, array $identifier, array $types = []): int
{
$this->connect('master');
......@@ -279,42 +280,42 @@ class MasterSlaveConnection extends Connection
/**
* {@inheritDoc}
*/
public function insert(string $table, array $data, array $types = []) : int
public function insert(string $table, array $data, array $types = []): int
{
$this->connect('master');
return parent::insert($table, $data, $types);
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
$this->connect('master');
return parent::exec($statement);
}
public function createSavepoint(string $savepoint) : void
public function createSavepoint(string $savepoint): void
{
$this->connect('master');
parent::createSavepoint($savepoint);
}
public function releaseSavepoint(string $savepoint) : void
public function releaseSavepoint(string $savepoint): void
{
$this->connect('master');
parent::releaseSavepoint($savepoint);
}
public function rollbackSavepoint(string $savepoint) : void
public function rollbackSavepoint(string $savepoint): void
{
$this->connect('master');
parent::rollbackSavepoint($savepoint);
}
public function query(string $sql) : ResultStatement
public function query(string $sql): Result
{
$this->connect('master');
assert($this->_conn instanceof DriverConnection);
......@@ -329,7 +330,7 @@ class MasterSlaveConnection extends Connection
return $statement;
}
public function prepare(string $sql) : Statement
public function prepare(string $sql): Statement
{
$this->connect('master');
......
......@@ -9,6 +9,7 @@ use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\Exception\DriverException;
use Exception;
use Throwable;
use function array_map;
use function bin2hex;
use function implode;
......@@ -26,7 +27,7 @@ class DBALException extends Exception
/**
* @param mixed[] $params
*/
public static function driverExceptionDuringQuery(Driver $driver, Throwable $driverEx, string $sql, array $params = []) : self
public static function driverExceptionDuringQuery(Driver $driver, Throwable $driverEx, string $sql, array $params = []): self
{
$messageFormat = <<<'MESSAGE'
An exception occurred while executing "%s"%s:
......@@ -44,12 +45,12 @@ MESSAGE;
return static::wrapException($driver, $driverEx, $message);
}
public static function driverException(Driver $driver, Throwable $driverEx) : self
public static function driverException(Driver $driver, Throwable $driverEx): self
{
return static::wrapException($driver, $driverEx, sprintf('An exception occurred in driver with message: %s', $driverEx->getMessage()));
}
private static function wrapException(Driver $driver, Throwable $driverEx, string $msg) : self
private static function wrapException(Driver $driver, Throwable $driverEx, string $msg): self
{
if ($driverEx instanceof DriverException) {
return $driverEx;
......@@ -68,9 +69,9 @@ MESSAGE;
*
* @param array<mixed, mixed> $params
*/
private static function formatParameters(array $params) : string
private static function formatParameters(array $params): string
{
return '[' . implode(', ', array_map(static function ($param) : string {
return '[' . implode(', ', array_map(static function ($param): string {
if (is_resource($param)) {
return (string) $param;
}
......
......@@ -29,7 +29,7 @@ interface Driver
string $username = '',
string $password = '',
array $driverOptions = []
) : DriverConnection;
): DriverConnection;
/**
* Gets the DatabasePlatform instance that provides all the metadata about
......@@ -37,11 +37,11 @@ interface Driver
*
* @return AbstractPlatform The database platform.
*/
public function getDatabasePlatform() : AbstractPlatform;
public function getDatabasePlatform(): AbstractPlatform;
/**
* Gets the SchemaManager that can be used to inspect and change the underlying
* database schema of the platform this driver connects to.
*/
public function getSchemaManager(Connection $conn) : AbstractSchemaManager;
public function getSchemaManager(Connection $conn): AbstractSchemaManager;
}
......@@ -16,12 +16,12 @@ use Doctrine\DBAL\Schema\DB2SchemaManager;
*/
abstract class AbstractDB2Driver implements Driver
{
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new DB2Platform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new DB2SchemaManager($conn);
}
......
......@@ -34,7 +34,7 @@ abstract class AbstractDriverException extends Exception implements DriverExcept
$this->sqlState = $sqlState;
}
public function getSQLState() : ?string
public function getSQLState(): ?string
{
return $this->sqlState;
}
......
......@@ -18,6 +18,7 @@ use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\MySqlSchemaManager;
use Doctrine\DBAL\VersionAwarePlatformDriver;
use function preg_match;
use function stripos;
use function version_compare;
......@@ -93,7 +94,7 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
private const CR_UNKNOWN_HOST = 2005;
/**#@-*/
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException
public function convertException(string $message, DriverExceptionInterface $exception): DriverException
{
switch ($exception->getCode()) {
case self::ER_LOCK_DEADLOCK:
......@@ -179,7 +180,7 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
*
* @throws DBALException
*/
public function createDatabasePlatformForVersion(string $version) : AbstractPlatform
public function createDatabasePlatformForVersion(string $version): AbstractPlatform
{
$mariadb = stripos($version, 'mariadb') !== false;
if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) {
......@@ -208,13 +209,15 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
*
* @throws DBALException
*/
private function getOracleMysqlVersionNumber(string $versionString) : string
private function getOracleMysqlVersionNumber(string $versionString): string
{
if (preg_match(
'/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/',
$versionString,
$versionParts
) === 0) {
if (
preg_match(
'/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/',
$versionString,
$versionParts
) === 0
) {
throw InvalidPlatformVersion::new(
$versionString,
'<major_version>.<minor_version>.<patch_version>'
......@@ -240,13 +243,15 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
*
* @throws DBALException
*/
private function getMariaDbMysqlVersionNumber(string $versionString) : string
private function getMariaDbMysqlVersionNumber(string $versionString): string
{
if (preg_match(
'/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
$versionString,
$versionParts
) === 0) {
if (
preg_match(
'/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
$versionString,
$versionParts
) === 0
) {
throw InvalidPlatformVersion::new(
$versionString,
'^(?:5\.5\.5-)?(mariadb-)?<major_version>.<minor_version>.<patch_version>'
......@@ -261,7 +266,7 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
*
* @return MySqlPlatform
*/
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new MySqlPlatform();
}
......@@ -271,7 +276,7 @@ abstract class AbstractMySQLDriver implements ExceptionConverterDriver, VersionA
*
* @return MySqlSchemaManager
*/
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new MySqlSchemaManager($conn);
}
......
......@@ -20,7 +20,7 @@ use Doctrine\DBAL\Schema\OracleSchemaManager;
*/
abstract class AbstractOracleDriver implements Driver, ExceptionConverterDriver
{
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException
public function convertException(string $message, DriverExceptionInterface $exception): DriverException
{
switch ($exception->getCode()) {
case 1:
......@@ -60,12 +60,12 @@ abstract class AbstractOracleDriver implements Driver, ExceptionConverterDriver
return new DriverException($message, $exception);
}
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new OraclePlatform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new OracleSchemaManager($conn);
}
......@@ -75,7 +75,7 @@ abstract class AbstractOracleDriver implements Driver, ExceptionConverterDriver
*
* @param mixed[] $params The connection parameters to return the Easy Connect String for.
*/
protected function getEasyConnectString(array $params) : string
protected function getEasyConnectString(array $params): string
{
return (string) EasyConnectString::fromConnectionParameters($params);
}
......
......@@ -23,7 +23,7 @@ final class EasyConnectString
$this->string = $string;
}
public function __toString() : string
public function __toString(): string
{
return $this->string;
}
......@@ -33,7 +33,7 @@ final class EasyConnectString
*
* @param mixed[] $params
*/
public static function fromArray(array $params) : self
public static function fromArray(array $params): self
{
return new self(self::renderParams($params));
}
......@@ -43,7 +43,7 @@ final class EasyConnectString
*
* @param mixed[] $params
*/
public static function fromConnectionParameters(array $params) : self
public static function fromConnectionParameters(array $params): self
{
if (isset($params['connectstring'])) {
return new self($params['connectstring']);
......@@ -90,7 +90,7 @@ final class EasyConnectString
/**
* @param mixed[] $params
*/
private static function renderParams(array $params) : string
private static function renderParams(array $params): string
{
$chunks = [];
......@@ -110,7 +110,7 @@ final class EasyConnectString
/**
* @param mixed $value
*/
private static function renderValue($value) : string
private static function renderValue($value): string
{
if (is_array($value)) {
return self::renderParams($value);
......
......@@ -15,6 +15,7 @@ use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
use Doctrine\DBAL\VersionAwarePlatformDriver;
use function preg_match;
use function strpos;
use function version_compare;
......@@ -29,7 +30,7 @@ abstract class AbstractPostgreSQLDriver implements ExceptionConverterDriver, Ver
*
* @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
*/
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException
public function convertException(string $message, DriverExceptionInterface $exception): DriverException
{
switch ($exception->getSQLState()) {
case '40001':
......@@ -80,7 +81,7 @@ abstract class AbstractPostgreSQLDriver implements ExceptionConverterDriver, Ver
return new DriverException($message, $exception);
}
public function createDatabasePlatformForVersion(string $version) : AbstractPlatform
public function createDatabasePlatformForVersion(string $version): AbstractPlatform
{
if (preg_match('/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/', $version, $versionParts) === 0) {
throw InvalidPlatformVersion::new(
......@@ -101,12 +102,12 @@ abstract class AbstractPostgreSQLDriver implements ExceptionConverterDriver, Ver
return new PostgreSQL94Platform();
}
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new PostgreSQL94Platform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new PostgreSqlSchemaManager($conn);
}
......
......@@ -14,6 +14,7 @@ use Doctrine\DBAL\Platforms\SQLAnywhere16Platform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SQLAnywhereSchemaManager;
use Doctrine\DBAL\VersionAwarePlatformDriver;
use function preg_match;
/**
......@@ -26,7 +27,7 @@ abstract class AbstractSQLAnywhereDriver implements ExceptionConverterDriver, Ve
*
* @link http://dcx.sybase.com/index.html#sa160/en/saerrors/sqlerror.html
*/
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException
public function convertException(string $message, DriverExceptionInterface $exception): DriverException
{
switch ($exception->getCode()) {
case -306:
......@@ -76,13 +77,15 @@ abstract class AbstractSQLAnywhereDriver implements ExceptionConverterDriver, Ve
return new DriverException($message, $exception);
}
public function createDatabasePlatformForVersion(string $version) : AbstractPlatform
public function createDatabasePlatformForVersion(string $version): AbstractPlatform
{
if (preg_match(
'/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+)(?:\.(?P<build>\d+))?)?)?/',
$version,
$versionParts
) === 0) {
if (
preg_match(
'/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+)(?:\.(?P<build>\d+))?)?)?/',
$version,
$versionParts
) === 0
) {
throw InvalidPlatformVersion::new(
$version,
'<major_version>.<minor_version>.<patch_version>.<build_version>'
......@@ -92,12 +95,12 @@ abstract class AbstractSQLAnywhereDriver implements ExceptionConverterDriver, Ve
return new SQLAnywhere16Platform();
}
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new SQLAnywhere16Platform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new SQLAnywhereSchemaManager($conn);
}
......
......@@ -16,12 +16,12 @@ use Doctrine\DBAL\Schema\SQLServerSchemaManager;
*/
abstract class AbstractSQLServerDriver implements Driver
{
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new SQLServer2012Platform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new SQLServerSchemaManager($conn);
}
......
......@@ -13,6 +13,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SqliteSchemaManager;
use function strpos;
/**
......@@ -25,13 +26,14 @@ abstract class AbstractSQLiteDriver implements Driver, ExceptionConverterDriver
*
* @link http://www.sqlite.org/c3ref/c_abort.html
*/
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException
public function convertException(string $message, DriverExceptionInterface $exception): DriverException
{
if (strpos($exception->getMessage(), 'database is locked') !== false) {
return new Exception\LockWaitTimeoutException($message, $exception);
}
if (strpos($exception->getMessage(), 'must be unique') !== false ||
if (
strpos($exception->getMessage(), 'must be unique') !== false ||
strpos($exception->getMessage(), 'is not unique') !== false ||
strpos($exception->getMessage(), 'are not unique') !== false ||
strpos($exception->getMessage(), 'UNIQUE constraint failed') !== false
......@@ -43,7 +45,8 @@ abstract class AbstractSQLiteDriver implements Driver, ExceptionConverterDriver
return new Exception\ForeignKeyConstraintViolationException($message, $exception);
}
if (strpos($exception->getMessage(), 'may not be NULL') !== false ||
if (
strpos($exception->getMessage(), 'may not be NULL') !== false ||
strpos($exception->getMessage(), 'NOT NULL constraint failed') !== false
) {
return new Exception\NotNullConstraintViolationException($message, $exception);
......@@ -80,12 +83,12 @@ abstract class AbstractSQLiteDriver implements Driver, ExceptionConverterDriver
return new DriverException($message, $exception);
}
public function getDatabasePlatform() : AbstractPlatform
public function getDatabasePlatform(): AbstractPlatform
{
return new SqlitePlatform();
}
public function getSchemaManager(Connection $conn) : AbstractSchemaManager
public function getSchemaManager(Connection $conn): AbstractSchemaManager
{
return new SqliteSchemaManager($conn);
}
......
......@@ -17,50 +17,50 @@ interface Connection
/**
* Prepares a statement for execution and returns a Statement object.
*/
public function prepare(string $sql) : Statement;
public function prepare(string $sql): Statement;
/**
* Executes an SQL statement, returning a result set as a Statement object.
*
* @throws DBALException
*/
public function query(string $sql) : ResultStatement;
public function query(string $sql): Result;
/**
* Quotes a string for use in a query.
*/
public function quote(string $input) : string;
public function quote(string $input): string;
/**
* Executes an SQL statement and return the number of affected rows.
*
* @throws DBALException
*/
public function exec(string $statement) : int;
public function exec(string $statement): int;
/**
* Returns the ID of the last inserted row or sequence value.
*/
public function lastInsertId(?string $name = null) : string;
public function lastInsertId(?string $name = null): string;
/**
* Initiates a transaction.
*
* @throws DriverException
*/
public function beginTransaction() : void;
public function beginTransaction(): void;
/**
* Commits a transaction.
*
* @throws DriverException
*/
public function commit() : void;
public function commit(): void;
/**
* Rolls back the current transaction, as initiated by beginTransaction().
*
* @throws DriverException
*/
public function rollBack() : void;
public function rollBack(): void;
}
......@@ -21,5 +21,5 @@ interface DriverException extends Throwable
*
* Returns null if the driver does not provide a SQLSTATE for the error occurred.
*/
public function getSQLState() : ?string;
public function getSQLState(): ?string;
}
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\DBALException;
use function sprintf;
/**
......@@ -12,7 +13,7 @@ use function sprintf;
*/
final class UnknownFetchMode extends DBALException
{
public static function new(int $fetchMode) : self
public static function new(int $fetchMode): self
{
return new self(sprintf('Unknown fetch mode %d.', $fetchMode));
}
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\DBALException;
use function sprintf;
/**
......@@ -12,7 +13,7 @@ use function sprintf;
*/
final class UnknownParamType extends DBALException
{
public static function new(int $type) : self
public static function new(int $type): self
{
return new self(sprintf('Unknown param type %d.', $type));
}
......
......@@ -23,5 +23,5 @@ interface ExceptionConverterDriver
*
* @return DriverException An instance of one of the DriverException subclasses.
*/
public function convertException(string $message, DriverExceptionInterface $exception) : DriverException;
public function convertException(string $message, DriverExceptionInterface $exception): DriverException;
}
......@@ -14,9 +14,9 @@ final class FetchUtils
*
* @throws DriverException
*/
public static function fetchOne(ResultStatement $stmt)
public static function fetchOne(Result $result)
{
$row = $stmt->fetchNumeric();
$row = $result->fetchNumeric();
if ($row === false) {
return false;
......@@ -30,11 +30,11 @@ final class FetchUtils
*
* @throws DriverException
*/
public static function fetchAllNumeric(ResultStatement $stmt) : array
public static function fetchAllNumeric(Result $result): array
{
$rows = [];
while (($row = $stmt->fetchNumeric()) !== false) {
while (($row = $result->fetchNumeric()) !== false) {
$rows[] = $row;
}
......@@ -46,11 +46,11 @@ final class FetchUtils
*
* @throws DriverException
*/
public static function fetchAllAssociative(ResultStatement $stmt) : array
public static function fetchAllAssociative(Result $result): array
{
$rows = [];
while (($row = $stmt->fetchAssociative()) !== false) {
while (($row = $result->fetchAssociative()) !== false) {
$rows[] = $row;
}
......@@ -62,11 +62,11 @@ final class FetchUtils
*
* @throws DriverException
*/
public static function fetchColumn(ResultStatement $stmt) : array
public static function fetchFirstColumn(Result $result): array
{
$rows = [];
while (($row = $stmt->fetchOne()) !== false) {
while (($row = $result->fetchOne()) !== false) {
$rows[] = $row;
}
......
......@@ -4,10 +4,11 @@ declare(strict_types=0);
namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use stdClass;
use function assert;
use function db2_autocommit;
use function db2_commit;
......@@ -20,6 +21,7 @@ use function db2_pconnect;
use function db2_prepare;
use function db2_rollback;
use function db2_server_info;
use const DB2_AUTOCOMMIT_OFF;
use const DB2_AUTOCOMMIT_ON;
......@@ -49,7 +51,7 @@ final class DB2Connection implements ServerInfoAwareConnection
$this->conn = $conn;
}
public function getServerVersion() : string
public function getServerVersion(): string
{
$serverInfo = db2_server_info($this->conn);
assert($serverInfo instanceof stdClass);
......@@ -57,7 +59,7 @@ final class DB2Connection implements ServerInfoAwareConnection
return $serverInfo->DBMS_VER;
}
public function prepare(string $sql) : DriverStatement
public function prepare(string $sql): DriverStatement
{
$stmt = @db2_prepare($this->conn, $sql);
if ($stmt === false) {
......@@ -67,20 +69,17 @@ final class DB2Connection implements ServerInfoAwareConnection
return new DB2Statement($stmt);
}
public function query(string $sql) : ResultStatement
public function query(string $sql): ResultInterface
{
$stmt = $this->prepare($sql);
$stmt->execute();
return $stmt;
return $this->prepare($sql)->execute();
}
public function quote(string $input) : string
public function quote(string $input): string
{
return "'" . db2_escape_string($input) . "'";
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
$stmt = @db2_exec($this->conn, $statement);
......@@ -91,19 +90,19 @@ final class DB2Connection implements ServerInfoAwareConnection
return db2_num_rows($stmt);
}
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
return db2_last_insert_id($this->conn);
}
public function beginTransaction() : void
public function beginTransaction(): void
{
if (db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF) !== true) {
throw DB2Exception::fromConnectionError($this->conn);
}
}
public function commit() : void
public function commit(): void
{
if (! db2_commit($this->conn)) {
throw DB2Exception::fromConnectionError($this->conn);
......@@ -114,7 +113,7 @@ final class DB2Connection implements ServerInfoAwareConnection
}
}
public function rollBack() : void
public function rollBack(): void
{
if (! db2_rollback($this->conn)) {
throw DB2Exception::fromConnectionError($this->conn);
......
......@@ -6,6 +6,7 @@ namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\AbstractDB2Driver;
use Doctrine\DBAL\Driver\Connection;
use function array_keys;
use function array_map;
use function implode;
......@@ -24,7 +25,7 @@ final class DB2Driver extends AbstractDB2Driver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if ($params['host'] !== 'localhost' && $params['host'] !== '127.0.0.1') {
// if the host isn't localhost, use extended connection params
$params['dbname'] = $this->buildConnectionString($params, $username, $password);
......@@ -38,7 +39,7 @@ final class DB2Driver extends AbstractDB2Driver
/**
* @param string[] $params
*/
private function buildConnectionString(array $params, string $username, string $password) : string
private function buildConnectionString(array $params, string $username, string $password): string
{
$connectionParams = [
'DRIVER' => '{IBM DB2 ODBC DRIVER}',
......@@ -53,7 +54,7 @@ final class DB2Driver extends AbstractDB2Driver
$connectionParams['PORT'] = $params['port'];
}
return implode(';', array_map(static function (string $key, string $value) : string {
return implode(';', array_map(static function (string $key, string $value): string {
return sprintf('%s=%s', $key, $value);
}, array_keys($connectionParams), $connectionParams));
}
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\AbstractDriverException;
use function db2_conn_error;
use function db2_conn_errormsg;
use function db2_stmt_error;
......@@ -18,7 +19,7 @@ class DB2Exception extends AbstractDriverException
/**
* @param resource|null $connection
*/
public static function fromConnectionError($connection = null) : self
public static function fromConnectionError($connection = null): self
{
if ($connection !== null) {
return new self(db2_conn_errormsg($connection), db2_conn_error($connection));
......@@ -30,7 +31,7 @@ class DB2Exception extends AbstractDriverException
/**
* @param resource|null $statement
*/
public static function fromStatementError($statement = null) : self
public static function fromStatementError($statement = null): self
{
if ($statement !== null) {
return new self(db2_stmt_errormsg($statement), db2_stmt_error($statement));
......
......@@ -4,17 +4,13 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
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_free_result;
use function db2_num_fields;
use function db2_num_rows;
use function error_get_last;
use function fclose;
use function fwrite;
......@@ -24,6 +20,7 @@ use function ksort;
use function stream_copy_to_stream;
use function stream_get_meta_data;
use function tmpfile;
use const DB2_BINARY;
use const DB2_CHAR;
use const DB2_LONG;
......@@ -46,13 +43,6 @@ final class DB2Statement implements Statement
*/
private $lobs = [];
/**
* Indicates whether the statement is in the state when fetching results is possible
*
* @var bool
*/
private $result = false;
/**
* @param resource $stmt
*/
......@@ -64,7 +54,7 @@ final class DB2Statement implements Statement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
$this->bindParam($param, $value, $type);
}
......@@ -72,7 +62,7 @@ final class DB2Statement implements Statement
/**
* {@inheritdoc}
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null): void
{
assert(is_int($param));
......@@ -101,34 +91,25 @@ final class DB2Statement implements Statement
}
}
public function closeCursor() : void
{
$this->bindParam = [];
if (! $this->result) {
return;
}
db2_free_result($this->stmt);
$this->result = false;
}
public function columnCount() : int
/**
* @param int $position Parameter position
* @param mixed $variable
*
* @throws DB2Exception
*/
private function bind(int $position, &$variable, int $parameterType, int $dataType): void
{
$count = db2_num_fields($this->stmt);
$this->bindParam[$position] =& $variable;
if ($count !== false) {
return $count;
if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) {
throw DB2Exception::fromStatementError($this->stmt);
}
return 0;
}
/**
* {@inheritdoc}
*/
public function execute(?array $params = null) : void
public function execute(?array $params = null): ResultInterface
{
if ($params === null) {
ksort($this->bindParam);
......@@ -150,7 +131,7 @@ final class DB2Statement implements Statement
$this->writeStringToStream($source, $target);
}
$retval = db2_execute($this->stmt, $params);
$result = db2_execute($this->stmt, $params);
foreach ($this->lobs as [, $handle]) {
fclose($handle);
......@@ -158,89 +139,11 @@ final class DB2Statement implements Statement
$this->lobs = [];
if ($retval === false) {
if ($result === false) {
throw DB2Exception::fromStatementError($this->stmt);
}
$this->result = true;
}
/**
* {@inheritDoc}
*/
public function fetchNumeric()
{
if (! $this->result) {
return false;
}
return db2_fetch_array($this->stmt);
}
/**
* {@inheritdoc}
*/
public function fetchAssociative()
{
// 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 db2_fetch_assoc($this->stmt);
}
/**
* {@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 fetchColumn() : array
{
return FetchUtils::fetchColumn($this);
}
public function rowCount() : int
{
return @db2_num_rows($this->stmt);
}
/**
* @param int $position Parameter position
* @param mixed $variable
*
* @throws DB2Exception
*/
private function bind(int $position, &$variable, int $parameterType, int $dataType) : void
{
$this->bindParam[$position] =& $variable;
if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) {
throw DB2Exception::fromStatementError($this->stmt);
}
return new Result($this->stmt);
}
/**
......@@ -265,7 +168,7 @@ final class DB2Statement implements Statement
*
* @throws DB2Exception
*/
private function copyStreamToStream($source, $target) : void
private function copyStreamToStream($source, $target): void
{
if (@stream_copy_to_stream($source, $target) === false) {
throw new DB2Exception('Could not copy source stream to temporary file: ' . error_get_last()['message']);
......@@ -277,7 +180,7 @@ final class DB2Statement implements Statement
*
* @throws DB2Exception
*/
private function writeStringToStream(string $string, $target) : void
private function writeStringToStream(string $string, $target): void
{
if (@fwrite($target, $string) === false) {
throw new DB2Exception('Could not write string to temporary file: ' . error_get_last()['message']);
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use function db2_fetch_array;
use function db2_fetch_assoc;
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;
final class Result implements ResultInterface
{
/** @var resource */
private $statement;
/**
* @param resource $statement
*/
public function __construct($statement)
{
$this->statement = $statement;
}
/**
* {@inheritDoc}
*/
public function fetchNumeric()
{
$row = @db2_fetch_array($this->statement);
if ($row === false && db2_stmt_error($this->statement) !== '02000') {
throw new DB2Exception(db2_stmt_errormsg($this->statement));
}
return $row;
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
$row = @db2_fetch_assoc($this->statement);
if ($row === false && db2_stmt_error($this->statement) !== '02000') {
throw new DB2Exception(db2_stmt_errormsg($this->statement));
}
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 fetchFirstColumn(): array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
return @db2_num_rows($this->statement);
}
public function columnCount(): int
{
$count = db2_num_fields($this->statement);
if ($count !== false) {
return $count;
}
return 0;
}
public function free(): void
{
db2_free_result($this->statement);
}
}
......@@ -18,7 +18,7 @@ final class Driver extends AbstractMySQLDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
try {
return new MysqliConnection($params, $username, $password, $driverOptions);
} catch (MysqliException $e) {
......
......@@ -12,7 +12,7 @@ use mysqli;
*/
final class ConnectionError extends MysqliException
{
public static function new(mysqli $connection) : self
public static function new(mysqli $connection): self
{
$connectionSQLState = $connection->sqlstate;
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
use Doctrine\DBAL\Driver\Mysqli\MysqliException;
use function sprintf;
/**
......@@ -12,7 +13,7 @@ use function sprintf;
*/
final class FailedReadingStreamOffset extends MysqliException
{
public static function new(int $offset) : self
public static function new(int $offset): self
{
return new self(sprintf('Failed reading the stream resource for parameter offset %d.', $offset));
}
......
......@@ -12,7 +12,7 @@ use mysqli_stmt;
*/
final class StatementError extends MysqliException
{
public static function new(mysqli_stmt $statement) : self
public static function new(mysqli_stmt $statement): self
{
return new self($statement->error, $statement->sqlstate, $statement->errno);
}
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
use Doctrine\DBAL\Driver\Mysqli\MysqliException;
use function sprintf;
/**
......@@ -12,7 +13,7 @@ use function sprintf;
*/
final class UnknownFetchMode extends MysqliException
{
public static function new(int $fetchMode) : self
public static function new(int $fetchMode): self
{
return new self(sprintf('Unknown fetch mode %d.', $fetchMode));
}
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
use Doctrine\DBAL\Driver\Mysqli\MysqliException;
use function sprintf;
/**
......@@ -15,7 +16,7 @@ final class UnknownType extends MysqliException
/**
* @param mixed $type
*/
public static function new($type) : self
public static function new($type): self
{
return new self(sprintf('Unknown type, %d given.', $type));
}
......
......@@ -11,7 +11,7 @@ namespace Doctrine\DBAL\Driver\Mysqli;
*/
final class HostRequired extends MysqliException
{
public static function forPersistentConnection() : self
public static function forPersistentConnection(): self
{
return new self('The "host" parameter is required for a persistent connection');
}
......
......@@ -6,10 +6,11 @@ namespace Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionError;
use Doctrine\DBAL\Driver\PingableConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use mysqli;
use function defined;
use function floor;
use function in_array;
......@@ -20,6 +21,7 @@ use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function stripos;
use const MYSQLI_INIT_COMMAND;
use const MYSQLI_OPT_CONNECT_TIMEOUT;
use const MYSQLI_OPT_LOCAL_INFILE;
......@@ -66,7 +68,7 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
$this->setSecureConnection($params);
$this->setDriverOptions($driverOptions);
set_error_handler(static function () : bool {
set_error_handler(static function (): bool {
return true;
});
......@@ -90,7 +92,7 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
*
* Could be used if part of your application is not using DBAL.
*/
public function getWrappedResourceHandle() : mysqli
public function getWrappedResourceHandle(): mysqli
{
return $this->conn;
}
......@@ -103,7 +105,7 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
*
* @link https://jira.mariadb.org/browse/MDEV-4088
*/
public function getServerVersion() : string
public function getServerVersion(): string
{
$serverInfos = $this->conn->get_server_info();
if (stripos($serverInfos, 'mariadb') !== false) {
......@@ -117,25 +119,22 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
}
public function prepare(string $sql) : DriverStatement
public function prepare(string $sql): DriverStatement
{
return new MysqliStatement($this->conn, $sql);
}
public function query(string $sql) : ResultStatement
public function query(string $sql): ResultInterface
{
$stmt = $this->prepare($sql);
$stmt->execute();
return $stmt;
return $this->prepare($sql)->execute();
}
public function quote(string $input) : string
public function quote(string $input): string
{
return "'" . $this->conn->escape_string($input) . "'";
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
if ($this->conn->query($statement) === false) {
throw ConnectionError::new($this->conn);
......@@ -144,24 +143,24 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
return $this->conn->affected_rows;
}
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
return (string) $this->conn->insert_id;
}
public function beginTransaction() : void
public function beginTransaction(): void
{
$this->conn->query('START TRANSACTION');
}
public function commit() : void
public function commit(): void
{
if (! $this->conn->commit()) {
throw ConnectionError::new($this->conn);
}
}
public function rollBack() : void
public function rollBack(): void
{
if (! $this->conn->rollback()) {
throw ConnectionError::new($this->conn);
......@@ -176,7 +175,7 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
* @throws MysqliException When one of of the options is not supported.
* @throws MysqliException When applying doesn't work - e.g. due to incorrect value.
*/
private function setDriverOptions(array $driverOptions = []) : void
private function setDriverOptions(array $driverOptions = []): void
{
$supportedDriverOptions = [
MYSQLI_OPT_CONNECT_TIMEOUT,
......@@ -216,7 +215,7 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
*
* {@inheritDoc}
*/
public function ping() : void
public function ping(): void
{
if (! $this->conn->ping()) {
throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno);
......@@ -230,9 +229,10 @@ class MysqliConnection implements PingableConnection, ServerInfoAwareConnection
*
* @throws MysqliException
*/
private function setSecureConnection(array $params) : void
private function setSecureConnection(array $params): void
{
if (! isset($params['ssl_key']) &&
if (
! isset($params['ssl_key']) &&
! isset($params['ssl_cert']) &&
! isset($params['ssl_ca']) &&
! isset($params['ssl_capath']) &&
......
......@@ -5,26 +5,23 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionError;
use Doctrine\DBAL\Driver\Mysqli\Exception\FailedReadingStreamOffset;
use Doctrine\DBAL\Driver\Mysqli\Exception\StatementError;
use Doctrine\DBAL\Driver\Mysqli\Exception\UnknownType;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Exception\InvalidArgumentException;
use Doctrine\DBAL\ParameterType;
use mysqli;
use mysqli_stmt;
use stdClass;
use function array_combine;
use function array_fill;
use function array_map;
use function assert;
use function count;
use function feof;
use function fread;
use function get_resource_type;
use function is_array;
use function is_int;
use function is_resource;
use function str_repeat;
......@@ -47,32 +44,6 @@ final class MysqliStatement implements Statement
/** @var mysqli_stmt */
private $stmt;
/**
* Whether the statement result metadata has been fetched.
*
* @var bool
*/
private $metadataFetched = false;
/**
* Whether the statement result has columns. The property should be used only after the result metadata
* has been fetched ({@see $metadataFetched}). Otherwise, the property value is undetermined.
*
* @var bool
*/
private $hasColumns = false;
/**
* Mapping of statement result column indexes to their names. The property should be used only
* if the statement result has columns ({@see $hasColumns}). Otherwise, the property value is undetermined.
*
* @var array<int,string>
*/
private $columnNames = [];
/** @var mixed[] */
private $rowBoundValues = [];
/** @var mixed[] */
private $boundValues = [];
......@@ -86,13 +57,6 @@ final class MysqliStatement implements Statement
*/
private $values = [];
/**
* Indicates whether the statement is in the state when fetching results is possible
*
* @var bool
*/
private $result = false;
/**
* @throws MysqliException
*/
......@@ -120,7 +84,7 @@ final class MysqliStatement implements Statement
/**
* {@inheritdoc}
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null): void
{
assert(is_int($param));
......@@ -135,7 +99,7 @@ final class MysqliStatement implements Statement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
assert(is_int($param));
......@@ -151,7 +115,7 @@ final class MysqliStatement implements Statement
/**
* {@inheritdoc}
*/
public function execute(?array $params = null) : void
public function execute(?array $params = null): ResultInterface
{
if ($params !== null && count($params) > 0) {
if (! $this->bindUntypedValues($params)) {
......@@ -165,56 +129,7 @@ final class MysqliStatement implements Statement
throw StatementError::new($this->stmt);
}
if (! $this->metadataFetched) {
$meta = $this->stmt->result_metadata();
if ($meta !== false) {
$this->hasColumns = true;
$fields = $meta->fetch_fields();
assert(is_array($fields));
$this->columnNames = array_map(static function (stdClass $field) : string {
return $field->name;
}, $fields);
$meta->free();
} else {
$this->hasColumns = false;
}
$this->metadataFetched = true;
}
if ($this->hasColumns) {
// Store result of every execution which has it. Otherwise it will be impossible
// to execute a new statement in case if the previous one has non-fetched rows
// @link http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html
$this->stmt->store_result();
// Bind row values _after_ storing the result. Otherwise, if mysqli is compiled with libmysql,
// it will have to allocate as much memory as it may be needed for the given column type
// (e.g. for a LONGBLOB field it's 4 gigabytes)
// @link https://bugs.php.net/bug.php?id=51386#1270673122
//
// Make sure that the values are bound after each execution. Otherwise, if closeCursor() has been
// previously called on the statement, the values are unbound making the statement unusable.
//
// It's also important that row values are bound after _each_ call to store_result(). Otherwise,
// if mysqli is compiled with libmysql, subsequently fetched string values will get truncated
// to the length of the ones fetched during the previous execution.
$this->rowBoundValues = array_fill(0, count($this->columnNames), null);
$refs = [];
foreach ($this->rowBoundValues as $key => &$value) {
$refs[$key] =& $value;
}
if (! $this->stmt->bind_result(...$refs)) {
throw StatementError::new($this->stmt);
}
}
$this->result = true;
return new Result($this->stmt);
}
/**
......@@ -222,7 +137,7 @@ final class MysqliStatement implements Statement
*
* @throws DriverException
*/
private function bindTypedParameters() : void
private function bindTypedParameters(): void
{
$streams = $values = [];
$types = $this->types;
......@@ -264,7 +179,7 @@ final class MysqliStatement implements Statement
*
* @throws MysqliException
*/
private function sendLongData(array $streams) : void
private function sendLongData(array $streams): void
{
foreach ($streams as $paramNr => $stream) {
while (! feof($stream)) {
......@@ -286,7 +201,7 @@ final class MysqliStatement implements Statement
*
* @param mixed[] $values
*/
private function bindUntypedValues(array $values) : bool
private function bindUntypedValues(array $values): bool
{
$params = [];
$types = str_repeat('s', count($values));
......@@ -297,116 +212,4 @@ final class MysqliStatement implements Statement
return $this->stmt->bind_param($types, ...$params);
}
/**
* @return mixed[]|false|null
*/
private function fetch()
{
$ret = $this->stmt->fetch();
if ($ret === true) {
$values = [];
foreach ($this->rowBoundValues as $v) {
$values[] = $v;
}
return $values;
}
return $ret;
}
/**
* {@inheritdoc}
*/
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 StatementError::new($this->stmt);
}
return $values;
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
$values = $this->fetchNumeric();
if ($values === false) {
return false;
}
$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 fetchColumn() : array
{
return FetchUtils::fetchColumn($this);
}
public function closeCursor() : void
{
$this->stmt->free_result();
$this->result = false;
}
public function rowCount() : int
{
if ($this->hasColumns) {
return $this->stmt->num_rows;
}
return $this->stmt->affected_rows;
}
public function columnCount() : int
{
return $this->stmt->field_count;
}
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use mysqli_stmt;
use stdClass;
use function array_combine;
use function array_fill;
use function array_map;
use function assert;
use function count;
use function is_array;
final class Result implements ResultInterface
{
/** @var mysqli_stmt */
private $statement;
/**
* Whether the statement result has columns. The property should be used only after the result metadata
* has been fetched ({@see $metadataFetched}). Otherwise, the property value is undetermined.
*
* @var bool
*/
private $hasColumns = false;
/**
* Mapping of statement result column indexes to their names. The property should be used only
* if the statement result has columns ({@see $hasColumns}). Otherwise, the property value is undetermined.
*
* @var array<int,string>
*/
private $columnNames = [];
/** @var mixed[] */
private $boundValues = [];
/**
* @throws MysqliException
*/
public function __construct(mysqli_stmt $statement)
{
$this->statement = $statement;
$meta = $statement->result_metadata();
if ($meta === false) {
return;
}
$this->hasColumns = true;
$fields = $meta->fetch_fields();
assert(is_array($fields));
$this->columnNames = array_map(static function (stdClass $field): string {
return $field->name;
}, $fields);
$meta->free();
// Store result of every execution which has it. Otherwise it will be impossible
// to execute a new statement in case if the previous one has non-fetched rows
// @link http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html
$this->statement->store_result();
// Bind row values _after_ storing the result. Otherwise, if mysqli is compiled with libmysql,
// it will have to allocate as much memory as it may be needed for the given column type
// (e.g. for a LONGBLOB field it's 4 gigabytes)
// @link https://bugs.php.net/bug.php?id=51386#1270673122
//
// Make sure that the values are bound after each execution. Otherwise, if free() has been
// previously called on the result, the values are unbound making the statement unusable.
//
// It's also important that row values are bound after _each_ call to store_result(). Otherwise,
// if mysqli is compiled with libmysql, subsequently fetched string values will get truncated
// to the length of the ones fetched during the previous execution.
$this->boundValues = array_fill(0, count($this->columnNames), null);
$refs = [];
foreach ($this->boundValues as &$value) {
$refs[] =& $value;
}
if (! $this->statement->bind_result(...$refs)) {
throw new MysqliException($this->statement->error, $this->statement->sqlstate, $this->statement->errno);
}
}
/**
* {@inheritdoc}
*/
public function fetchNumeric()
{
$ret = $this->statement->fetch();
if ($ret === false) {
throw new MysqliException($this->statement->error, $this->statement->sqlstate, $this->statement->errno);
}
if ($ret === null) {
return false;
}
$values = [];
foreach ($this->boundValues as $v) {
$values[] = $v;
}
return $values;
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
$values = $this->fetchNumeric();
if ($values === false) {
return false;
}
$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 fetchFirstColumn(): array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
if ($this->hasColumns) {
return $this->statement->num_rows;
}
return $this->statement->affected_rows;
}
public function columnCount(): int
{
return $this->statement->field_count;
}
public function free(): void
{
$this->statement->free_result();
}
}
......@@ -9,6 +9,7 @@ use function implode;
use function preg_match;
use function preg_quote;
use function substr;
use const PREG_OFFSET_CAPTURE;
/**
......@@ -30,7 +31,7 @@ final class ConvertPositionalToNamedPlaceholders
*
* @throws OCI8Exception
*/
public function __invoke(string $statement) : array
public function __invoke(string $statement): array
{
$fragmentOffset = $tokenOffset = 0;
$fragments = $paramMap = [];
......@@ -81,7 +82,7 @@ final class ConvertPositionalToNamedPlaceholders
array &$fragments,
?string &$currentLiteralDelimiter,
array &$paramMap
) : bool {
): bool {
$token = $this->findToken($statement, $tokenOffset, '/[?\'"]/');
if ($token === null) {
......@@ -119,7 +120,7 @@ final class ConvertPositionalToNamedPlaceholders
string $statement,
int &$tokenOffset,
string &$currentLiteralDelimiter
) : bool {
): bool {
$token = $this->findToken(
$statement,
$tokenOffset,
......@@ -146,7 +147,7 @@ final class ConvertPositionalToNamedPlaceholders
*
* @return string|null Token or NULL if not found
*/
private function findToken(string $statement, int &$offset, string $regex) : ?string
private function findToken(string $statement, int &$offset, string $regex): ?string
{
if (preg_match($regex, $statement, $matches, PREG_OFFSET_CAPTURE, $offset) === 1) {
$offset = $matches[0][1];
......
......@@ -7,6 +7,7 @@ namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractOracleDriver;
use Doctrine\DBAL\Driver\Connection;
use const OCI_NO_AUTO_COMMIT;
/**
......@@ -22,7 +23,7 @@ final class Driver extends AbstractOracleDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
try {
return new OCI8Connection(
$username,
......@@ -44,7 +45,7 @@ final class Driver extends AbstractOracleDriver
*
* @return string The DSN.
*/
private function constructDsn(array $params) : string
private function constructDsn(array $params): string
{
return $this->getEasyConnectString($params);
}
......
......@@ -14,17 +14,17 @@ final class ExecutionMode
/** @var bool */
private $isAutoCommitEnabled = true;
public function enableAutoCommit() : void
public function enableAutoCommit(): void
{
$this->isAutoCommitEnabled = true;
}
public function disableAutoCommit() : void
public function disableAutoCommit(): void
{
$this->isAutoCommitEnabled = false;
}
public function isAutoCommitEnabled() : bool
public function isAutoCommitEnabled(): bool
{
return $this->isAutoCommitEnabled;
}
......
......@@ -11,7 +11,7 @@ use function sprintf;
*/
final class NonTerminatedStringLiteral extends OCI8Exception
{
public static function new(int $offset) : self
public static function new(int $offset): self
{
return new self(
sprintf(
......
......@@ -5,10 +5,11 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use UnexpectedValueException;
use function addcslashes;
use function oci_commit;
use function oci_connect;
......@@ -19,6 +20,7 @@ use function oci_server_version;
use function preg_match;
use function sprintf;
use function str_replace;
use const OCI_NO_AUTO_COMMIT;
/**
......@@ -65,7 +67,7 @@ final class OCI8Connection implements Connection, ServerInfoAwareConnection
* @throws UnexpectedValueException If the version string returned by the database server
* does not contain a parsable version number.
*/
public function getServerVersion() : string
public function getServerVersion(): string
{
$version = oci_server_version($this->connection);
......@@ -86,33 +88,27 @@ final class OCI8Connection implements Connection, ServerInfoAwareConnection
return $matches[1];
}
public function prepare(string $sql) : DriverStatement
public function prepare(string $sql): DriverStatement
{
return new OCI8Statement($this->connection, $sql, $this->executionMode);
}
public function query(string $sql) : ResultStatement
public function query(string $sql): ResultInterface
{
$stmt = $this->prepare($sql);
$stmt->execute();
return $stmt;
return $this->prepare($sql)->execute();
}
public function quote(string $input) : string
public function quote(string $input): string
{
return "'" . addcslashes(str_replace("'", "''", $input), "\000\n\r\\\032") . "'";
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
$stmt = $this->prepare($statement);
$stmt->execute();
return $stmt->rowCount();
return $this->prepare($statement)->execute()->rowCount();
}
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
if ($name === null) {
throw new OCI8Exception('The driver does not support identity columns.');
......@@ -127,12 +123,12 @@ final class OCI8Connection implements Connection, ServerInfoAwareConnection
return $result;
}
public function beginTransaction() : void
public function beginTransaction(): void
{
$this->executionMode->disableAutoCommit();
}
public function commit() : void
public function commit(): void
{
if (! oci_commit($this->connection)) {
throw OCI8Exception::fromErrorInfo(oci_error($this->connection));
......@@ -141,7 +137,7 @@ final class OCI8Connection implements Connection, ServerInfoAwareConnection
$this->executionMode->enableAutoCommit();
}
public function rollBack() : void
public function rollBack(): void
{
if (! oci_rollback($this->connection)) {
throw OCI8Exception::fromErrorInfo(oci_error($this->connection));
......
......@@ -14,7 +14,7 @@ class OCI8Exception extends AbstractDriverException
/**
* @param mixed[]|false $error
*/
public static function fromErrorInfo($error) : self
public static function fromErrorInfo($error): self
{
if ($error === false) {
return new self('Database error occurred but no error information was retrieved from the driver.');
......
......@@ -4,34 +4,25 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
use function assert;
use function is_int;
use function is_resource;
use function oci_bind_by_name;
use function oci_cancel;
use function oci_error;
use function oci_execute;
use function oci_fetch_all;
use function oci_fetch_array;
use function oci_new_descriptor;
use function oci_num_fields;
use function oci_num_rows;
use function oci_parse;
use function sprintf;
use const OCI_ASSOC;
use const OCI_B_BIN;
use const OCI_B_BLOB;
use const OCI_COMMIT_ON_SUCCESS;
use const OCI_D_LOB;
use const OCI_FETCHSTATEMENT_BY_COLUMN;
use const OCI_FETCHSTATEMENT_BY_ROW;
use const OCI_NO_AUTO_COMMIT;
use const OCI_NUM;
use const OCI_RETURN_LOBS;
use const OCI_RETURN_NULLS;
use const OCI_TEMP_BLOB;
use const SQLT_CHR;
......@@ -61,13 +52,6 @@ final class OCI8Statement implements Statement
*/
private $boundValues = [];
/**
* Indicates whether the statement is in the state when fetching results is possible
*
* @var bool
*/
private $result = false;
/**
* Creates a new OCI8Statement that uses the given connection handle and SQL statement.
*
......@@ -92,7 +76,7 @@ final class OCI8Statement implements Statement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
$this->bindParam($param, $value, $type, null);
}
......@@ -100,7 +84,7 @@ final class OCI8Statement implements Statement
/**
* {@inheritdoc}
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null): void
{
if (is_int($param)) {
if (! isset($this->parameterMap[$param])) {
......@@ -123,13 +107,15 @@ final class OCI8Statement implements Statement
$this->boundValues[$param] =& $variable;
if (! oci_bind_by_name(
$this->statement,
$param,
$variable,
$length ?? -1,
$this->convertParameterType($type)
)) {
if (
! oci_bind_by_name(
$this->statement,
$param,
$variable,
$length ?? -1,
$this->convertParameterType($type)
)
) {
throw OCI8Exception::fromErrorInfo(oci_error($this->statement));
}
}
......@@ -137,7 +123,7 @@ final class OCI8Statement implements Statement
/**
* Converts DBAL parameter type to oci8 parameter type
*/
private function convertParameterType(int $type) : int
private function convertParameterType(int $type): int
{
switch ($type) {
case ParameterType::BINARY:
......@@ -151,33 +137,10 @@ final class OCI8Statement implements Statement
}
}
public function closeCursor() : void
{
// not having the result means there's nothing to close
if (! $this->result) {
return;
}
oci_cancel($this->statement);
$this->result = false;
}
public function columnCount() : int
{
$count = oci_num_fields($this->statement);
if ($count !== false) {
return $count;
}
return 0;
}
/**
* {@inheritdoc}
*/
public function execute(?array $params = null) : void
public function execute(?array $params = null): ResultInterface
{
if ($params !== null) {
foreach ($params as $key => $val) {
......@@ -202,104 +165,6 @@ final class OCI8Statement implements Statement
throw OCI8Exception::fromErrorInfo(oci_error($this->statement));
}
$this->result = true;
}
public function rowCount() : int
{
$count = oci_num_rows($this->statement);
if ($count !== false) {
return $count;
}
return 0;
}
/**
* {@inheritdoc}
*/
public function fetchNumeric()
{
return $this->fetch(OCI_NUM);
}
/**
* {@inheritdoc}
*/
public function fetchAssociative()
{
return $this->fetch(OCI_ASSOC);
}
/**
* {@inheritdoc}
*/
public function fetchOne()
{
return FetchUtils::fetchOne($this);
}
/**
* {@inheritdoc}
*/
public function fetchAllNumeric() : array
{
return $this->fetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW);
}
/**
* {@inheritdoc}
*/
public function fetchAllAssociative() : array
{
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 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
if (! $this->result) {
return false;
}
return oci_fetch_array(
$this->statement,
$mode | OCI_RETURN_NULLS | OCI_RETURN_LOBS
);
}
/**
* @return array<mixed>
*/
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
if (! $this->result) {
return [];
}
oci_fetch_all(
$this->statement,
$result,
0,
-1,
$mode | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS
);
return $result;
return new Result($this->statement);
}
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use function oci_cancel;
use function oci_fetch_all;
use function oci_fetch_array;
use function oci_num_fields;
use function oci_num_rows;
use const OCI_ASSOC;
use const OCI_FETCHSTATEMENT_BY_COLUMN;
use const OCI_FETCHSTATEMENT_BY_ROW;
use const OCI_NUM;
use const OCI_RETURN_LOBS;
use const OCI_RETURN_NULLS;
final class Result implements ResultInterface
{
/** @var resource */
private $statement;
/**
* @param resource $statement
*/
public function __construct($statement)
{
$this->statement = $statement;
}
/**
* {@inheritDoc}
*/
public function fetchNumeric()
{
return $this->fetch(OCI_NUM);
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
return $this->fetch(OCI_ASSOC);
}
/**
* {@inheritDoc}
*/
public function fetchOne()
{
return FetchUtils::fetchOne($this);
}
/**
* {@inheritDoc}
*/
public function fetchAllNumeric(): array
{
return $this->fetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_ROW);
}
/**
* {@inheritDoc}
*/
public function fetchAllAssociative(): array
{
return $this->fetchAll(OCI_ASSOC, OCI_FETCHSTATEMENT_BY_ROW);
}
/**
* {@inheritDoc}
*/
public function fetchFirstColumn(): array
{
return $this->fetchAll(OCI_NUM, OCI_FETCHSTATEMENT_BY_COLUMN)[0];
}
public function rowCount(): int
{
$count = oci_num_rows($this->statement);
if ($count !== false) {
return $count;
}
return 0;
}
public function columnCount(): int
{
$count = oci_num_fields($this->statement);
if ($count !== false) {
return $count;
}
return 0;
}
public function free(): void
{
oci_cancel($this->statement);
}
/**
* @return mixed|false
*/
private function fetch(int $mode)
{
return oci_fetch_array(
$this->statement,
$mode | OCI_RETURN_NULLS | OCI_RETURN_LOBS
);
}
/**
* @return array<mixed>
*/
private function fetchAll(int $mode, int $fetchStructure): array
{
oci_fetch_all(
$this->statement,
$result,
0,
-1,
$mode | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS
);
return $result;
}
}
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\PDO;
use Doctrine\DBAL\Driver\PDOException;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use PDO;
use PDOStatement;
use function assert;
use function is_array;
final class Result implements ResultInterface
{
/** @var PDOStatement */
private $statement;
public function __construct(PDOStatement $statement)
{
$this->statement = $statement;
}
/**
* {@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);
}
/**
* {@inheritDoc}
*/
public function fetchFirstColumn(): array
{
return $this->fetchAll(PDO::FETCH_COLUMN);
}
public function rowCount(): int
{
try {
return $this->statement->rowCount();
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
public function columnCount(): int
{
try {
return $this->statement->columnCount();
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
public function free(): void
{
try {
$this->statement->closeCursor();
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
* @return mixed|false
*
* @throws PDOException
*/
private function fetch(int $mode)
{
try {
return $this->statement->fetch($mode);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
* @return array<int,mixed>
*
* @throws PDOException
*/
private function fetchAll(int $mode): array
{
try {
$data = $this->statement->fetchAll($mode);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
assert(is_array($data));
return $data;
}
}
......@@ -4,7 +4,10 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\PDO\Result;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use PDO;
use function assert;
/**
......@@ -32,7 +35,7 @@ class PDOConnection implements ServerInfoAwareConnection
}
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
try {
return $this->connection->exec($statement);
......@@ -41,12 +44,12 @@ class PDOConnection implements ServerInfoAwareConnection
}
}
public function getServerVersion() : string
public function getServerVersion(): string
{
return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);
}
public function prepare(string $sql) : Statement
public function prepare(string $sql): Statement
{
try {
return $this->createStatement(
......@@ -57,24 +60,24 @@ class PDOConnection implements ServerInfoAwareConnection
}
}
public function query(string $sql) : ResultStatement
public function query(string $sql): ResultInterface
{
try {
$stmt = $this->connection->query($sql);
assert($stmt instanceof \PDOStatement);
return $this->createStatement($stmt);
return new Result($stmt);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
public function quote(string $input) : string
public function quote(string $input): string
{
return $this->connection->quote($input);
}
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
try {
if ($name === null) {
......@@ -90,27 +93,27 @@ class PDOConnection implements ServerInfoAwareConnection
/**
* Creates a wrapped statement
*/
protected function createStatement(\PDOStatement $stmt) : PDOStatement
protected function createStatement(\PDOStatement $stmt): PDOStatement
{
return new PDOStatement($stmt);
}
public function beginTransaction() : void
public function beginTransaction(): void
{
$this->connection->beginTransaction();
}
public function commit() : void
public function commit(): void
{
$this->connection->commit();
}
public function rollBack() : void
public function rollBack(): void
{
$this->connection->rollBack();
}
public function getWrappedConnection() : PDO
public function getWrappedConnection(): PDO
{
return $this->connection;
}
......
......@@ -24,7 +24,7 @@ final class Driver extends AbstractMySQLDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
......@@ -50,7 +50,7 @@ final class Driver extends AbstractMySQLDriver
*
* @return string The DSN.
*/
private function constructPdoDsn(array $params) : string
private function constructPdoDsn(array $params): string
{
$dsn = 'mysql:';
if (isset($params['host']) && $params['host'] !== '') {
......
......@@ -29,7 +29,7 @@ final class Driver extends AbstractOracleDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
......@@ -53,7 +53,7 @@ final class Driver extends AbstractOracleDriver
*
* @return string The DSN.
*/
private function constructPdoDsn(array $params) : string
private function constructPdoDsn(array $params): string
{
$dsn = 'oci:dbname=' . $this->getEasyConnectString($params);
......
......@@ -10,6 +10,7 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOException;
use PDO;
use function defined;
/**
......@@ -25,7 +26,7 @@ final class Driver extends AbstractPostgreSQLDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
......@@ -38,7 +39,8 @@ final class Driver extends AbstractPostgreSQLDriver
$driverOptions
);
if (defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')
if (
defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')
&& (! isset($driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES])
|| $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true
)
......@@ -67,7 +69,7 @@ final class Driver extends AbstractPostgreSQLDriver
*
* @return string The DSN.
*/
private function constructPdoDsn(array $params) : string
private function constructPdoDsn(array $params): string
{
$dsn = 'pgsql:';
......
......@@ -10,6 +10,7 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOException;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use function array_merge;
/**
......@@ -32,7 +33,7 @@ final class Driver extends AbstractSQLiteDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if (isset($driverOptions['userDefinedFunctions'])) {
$this->userDefinedFunctions = array_merge(
$this->userDefinedFunctions,
......@@ -68,7 +69,7 @@ final class Driver extends AbstractSQLiteDriver
*
* @return string The DSN.
*/
private function constructPdoDsn(array $params) : string
private function constructPdoDsn(array $params): string
{
$dsn = 'sqlite:';
if (isset($params['path'])) {
......
......@@ -6,6 +6,7 @@ namespace Doctrine\DBAL\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOStatement;
use function strpos;
use function substr;
......@@ -14,19 +15,18 @@ use function substr;
*/
class Connection extends PDOConnection
{
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
if ($name === null) {
return parent::lastInsertId($name);
}
$stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?');
$stmt->execute([$name]);
return $stmt->fetchOne();
return $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?')
->execute([$name])
->fetchOne();
}
public function quote(string $input) : string
public function quote(string $input): string
{
$val = parent::quote($input);
......@@ -38,7 +38,7 @@ class Connection extends PDOConnection
return $val;
}
protected function createStatement(\PDOStatement $stmt) : PDOStatement
protected function createStatement(\PDOStatement $stmt): PDOStatement
{
return new Statement($stmt);
}
......
......@@ -7,6 +7,7 @@ namespace Doctrine\DBAL\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver\AbstractSQLServerDriver;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use PDO;
use function is_int;
use function sprintf;
......@@ -23,7 +24,7 @@ final class Driver extends AbstractSQLServerDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : DriverConnection {
): DriverConnection {
$pdoOptions = $dsnOptions = [];
foreach ($driverOptions as $option => $value) {
......@@ -54,7 +55,7 @@ final class Driver extends AbstractSQLServerDriver
*
* @return string The DSN.
*/
private function constructPdoDsn(array $params, array $connectionOptions) : string
private function constructPdoDsn(array $params, array $connectionOptions): string
{
$dsn = 'sqlsrv:server=';
......@@ -82,7 +83,7 @@ final class Driver extends AbstractSQLServerDriver
*
* @param string[] $connectionOptions
*/
private function getConnectionOptionsDsn(array $connectionOptions) : string
private function getConnectionOptionsDsn(array $connectionOptions): string
{
$connectionOptionsDsn = '';
......
......@@ -16,9 +16,10 @@ final class Statement extends PDOStatement
/**
* {@inheritdoc}
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null): void
{
if (($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY)
if (
($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY)
&& $driverOptions === null
) {
$driverOptions = PDO::SQLSRV_ENCODING_BINARY;
......@@ -30,7 +31,7 @@ final class Statement extends PDOStatement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
$this->bindParam($param, $value, $type);
}
......
......@@ -5,13 +5,14 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Exception\UnknownParamType;
use Doctrine\DBAL\Driver\PDO\Result;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\ParameterType;
use PDO;
use function array_slice;
use function assert;
use function count;
use function func_get_args;
use function is_array;
/**
* The PDO implementation of the Statement interface.
......@@ -39,7 +40,7 @@ class PDOStatement implements Statement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
$type = $this->convertParamType($type);
......@@ -55,7 +56,7 @@ class PDOStatement implements Statement
* @param mixed $variable
* @param mixed $driverOptions
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null, $driverOptions = null): void
{
$type = $this->convertParamType($type);
$extraParameters = array_slice(func_get_args(), 3);
......@@ -71,111 +72,18 @@ class PDOStatement implements Statement
}
}
public function closeCursor() : void
{
$this->stmt->closeCursor();
}
public function columnCount() : int
{
return $this->stmt->columnCount();
}
/**
* {@inheritdoc}
*/
public function execute(?array $params = null) : void
public function execute(?array $params = null): ResultInterface
{
try {
$this->stmt->execute($params);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
public function rowCount() : int
{
return $this->stmt->rowCount();
}
/**
* {@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);
}
/**
* {@inheritdoc}
*/
public function fetchColumn() : array
{
return $this->fetchAll(PDO::FETCH_COLUMN);
}
/**
* @return mixed|false
*
* @throws PDOException
*/
private function fetch(int $mode)
{
try {
return $this->stmt->fetch($mode);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
}
/**
* @return array<int,mixed>
*
* @throws PDOException
*/
private function fetchAll(int $mode) : array
{
try {
$data = $this->stmt->fetchAll($mode);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
assert(is_array($data));
return $data;
return new Result($this->stmt);
}
/**
......@@ -183,7 +91,7 @@ class PDOStatement implements Statement
*
* @param int $type Parameter type
*/
private function convertParamType(int $type) : int
private function convertParamType(int $type): int
{
if (! isset(self::PARAM_TYPE_MAP[$type])) {
throw UnknownParamType::new($type);
......
......@@ -15,5 +15,5 @@ interface PingableConnection extends Connection
*
* @throws DriverException
*/
public function ping() : void;
public function ping(): void;
}
......@@ -5,37 +5,12 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver;
/**
* Interface for the reading part of a prepare statement only.
* Driver-level statement execution result.
*/
interface ResultStatement
interface Result
{
/**
* Closes the cursor, enabling the statement to be executed again.
*/
public function closeCursor() : void;
/**
* Returns the number of columns in the result set
*
* @return int The number of columns in the result set represented
* by the statement. If there is no result set,
* this method should return 0.
*/
public function columnCount() : int;
/**
* 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.
* Returns the next row of the result as a numeric array or FALSE if there are no more rows.
*
* @return array<int,mixed>|false
*
......@@ -44,7 +19,7 @@ interface ResultStatement
public function fetchNumeric();
/**
* Returns the next row of a result set as an associative array or FALSE if there are no more rows.
* Returns the next row of the result as an associative array or FALSE if there are no more rows.
*
* @return array<string,mixed>|false
*
......@@ -53,7 +28,7 @@ interface ResultStatement
public function fetchAssociative();
/**
* Returns the first value of the next row of a result set or FALSE if there are no more rows.
* Returns the first value of the next row of the result or FALSE if there are no more rows.
*
* @return mixed|false
*
......@@ -62,29 +37,53 @@ interface ResultStatement
public function fetchOne();
/**
* Returns an array containing all of the result set rows represented as numeric arrays.
* Returns an array containing all of the result rows represented as numeric arrays.
*
* @return array<int,array<int,mixed>>
*
* @throws DriverException
*/
public function fetchAllNumeric() : array;
public function fetchAllNumeric(): array;
/**
* Returns an array containing all of the result set rows represented as associative arrays.
* Returns an array containing all of the result rows represented as associative arrays.
*
* @return array<int,array<string,mixed>>
*
* @throws DriverException
*/
public function fetchAllAssociative() : array;
public function fetchAllAssociative(): array;
/**
* Returns an array containing the values of the first column of the result set.
* Returns an array containing the values of the first column of the result.
*
* @return array<int,mixed>
*
* @throws DriverException
*/
public function fetchColumn() : array;
public function fetchFirstColumn(): array;
/**
* Returns the number of rows affected by the DELETE, INSERT, or UPDATE statement that produced the result.
*
* If the statement executed a SELECT query or a similar platform-specific SQL (e.g. DESCRIBE, SHOW, etc.),
* some database drivers may return the number of rows returned by that query. However, this behaviour
* is not guaranteed for all drivers and should not be relied on in portable applications.
*
* @return int The number of rows.
*/
public function rowCount(): int;
/**
* Returns the number of columns in the result
*
* @return int The number of columns in the result. If the columns cannot be counted,
* this method must return 0.
*/
public function columnCount(): int;
/**
* Discards the non-fetched portion of the result, enabling the originating statement to be executed again.
*/
public function free(): void;
}
......@@ -7,6 +7,7 @@ namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver;
use Doctrine\DBAL\Driver\Connection;
use function array_keys;
use function array_map;
use function array_merge;
......@@ -28,7 +29,7 @@ final class Driver extends AbstractSQLAnywhereDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
try {
return new SQLAnywhereConnection(
$this->buildDsn($params, $username, $password, $driverOptions),
......@@ -47,7 +48,7 @@ final class Driver extends AbstractSQLAnywhereDriver
* @param string $password Password to use for connection authentication.
* @param mixed[] $driverOptions Additional parameters to use for the connection.
*/
private function buildDsn(array $params, string $username, string $password, array $driverOptions = []) : string
private function buildDsn(array $params, string $username, string $password, array $driverOptions = []): string
{
$connectionParams = [];
......@@ -74,7 +75,7 @@ final class Driver extends AbstractSQLAnywhereDriver
$connectionParams = array_merge($connectionParams, $driverOptions);
return implode(';', array_map(static function (string $key, string $value) : string {
return implode(';', array_map(static function (string $key, string $value): string {
return sprintf('%s=%s', $key, $value);
}, array_keys($connectionParams), $connectionParams));
}
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use function sasql_fetch_assoc;
use function sasql_fetch_row;
use function sasql_stmt_affected_rows;
use function sasql_stmt_field_count;
use function sasql_stmt_reset;
use function sasql_stmt_result_metadata;
final class Result implements ResultInterface
{
/** @var resource */
private $statement;
/** @var resource */
private $result;
/**
* @param resource $statement
*/
public function __construct($statement)
{
$this->statement = $statement;
$this->result = sasql_stmt_result_metadata($statement);
}
/**
* {@inheritDoc}
*/
public function fetchNumeric()
{
return sasql_fetch_row($this->result);
}
/**
* {@inheritDoc}
*/
public function fetchAssociative()
{
return sasql_fetch_assoc($this->result);
}
/**
* {@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 fetchFirstColumn(): array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount(): int
{
return sasql_stmt_affected_rows($this->statement);
}
public function columnCount(): int
{
return sasql_stmt_field_count($this->statement);
}
public function free(): void
{
sasql_stmt_reset($this->statement);
}
}
......@@ -4,9 +4,10 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\Driver\Statement;
use function assert;
use function is_resource;
use function is_string;
......@@ -60,7 +61,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
*
* @throws SQLAnywhereException
*/
public function beginTransaction() : void
public function beginTransaction(): void
{
if (! sasql_set_option($this->connection, 'auto_commit', 'off')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
......@@ -72,7 +73,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
*
* @throws SQLAnywhereException
*/
public function commit() : void
public function commit(): void
{
if (! sasql_commit($this->connection)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
......@@ -81,7 +82,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
$this->endTransaction();
}
public function exec(string $statement) : int
public function exec(string $statement): int
{
if (sasql_real_query($this->connection, $statement) === false) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
......@@ -90,7 +91,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
return sasql_affected_rows($this->connection);
}
public function getServerVersion() : string
public function getServerVersion(): string
{
$version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchOne();
assert(is_string($version));
......@@ -98,7 +99,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
return $version;
}
public function lastInsertId(?string $name = null) : string
public function lastInsertId(?string $name = null): string
{
if ($name === null) {
return sasql_insert_id($this->connection);
......@@ -107,20 +108,17 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
return $this->query('SELECT ' . $name . '.CURRVAL')->fetchOne();
}
public function prepare(string $sql) : DriverStatement
public function prepare(string $sql): Statement
{
return new SQLAnywhereStatement($this->connection, $sql);
}
public function query(string $sql) : ResultStatement
public function query(string $sql): ResultInterface
{
$stmt = $this->prepare($sql);
$stmt->execute();
return $stmt;
return $this->prepare($sql)->execute();
}
public function quote(string $input) : string
public function quote(string $input): string
{
return "'" . sasql_escape_string($this->connection, $input) . "'";
}
......@@ -130,7 +128,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
*
* @throws SQLAnywhereException
*/
public function rollBack() : void
public function rollBack(): void
{
if (! sasql_rollback($this->connection)) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
......@@ -144,7 +142,7 @@ final class SQLAnywhereConnection implements ServerInfoAwareConnection
*
* @throws SQLAnywhereException
*/
private function endTransaction() : void
private function endTransaction(): void
{
if (! sasql_set_option($this->connection, 'auto_commit', 'on')) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\AbstractDriverException;
use function sasql_error;
use function sasql_errorcode;
use function sasql_sqlstate;
......@@ -24,7 +25,7 @@ class SQLAnywhereException extends AbstractDriverException
* @param resource|null $conn The SQL Anywhere connection resource to retrieve the last error from.
* @param resource|null $stmt The SQL Anywhere statement resource to retrieve the last error from.
*/
public static function fromSQLAnywhereError($conn = null, $stmt = null) : self
public static function fromSQLAnywhereError($conn = null, $stmt = null): self
{
$state = $conn !== null ? sasql_sqlstate($conn) : sasql_sqlstate();
$code = 0;
......
......@@ -4,24 +4,18 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Exception\GetVariableType;
use Doctrine\DBAL\ParameterType;
use function array_key_exists;
use function assert;
use function is_int;
use function is_resource;
use function sasql_fetch_assoc;
use function sasql_fetch_row;
use function sasql_prepare;
use function sasql_stmt_affected_rows;
use function sasql_stmt_bind_param_ex;
use function sasql_stmt_execute;
use function sasql_stmt_field_count;
use function sasql_stmt_reset;
use function sasql_stmt_result_metadata;
use function sprintf;
/**
......@@ -32,9 +26,6 @@ final class SQLAnywhereStatement implements Statement
/** @var resource The connection resource. */
private $conn;
/** @var resource|null The result set resource to fetch. */
private $result;
/** @var resource The prepared SQL statement to execute. */
private $stmt;
......@@ -71,7 +62,7 @@ final class SQLAnywhereStatement implements Statement
*
* @throws SQLAnywhereException
*/
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void
public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null): void
{
assert(is_int($param));
......@@ -105,27 +96,17 @@ final class SQLAnywhereStatement implements Statement
/**
* {@inheritdoc}
*/
public function bindValue($param, $value, int $type = ParameterType::STRING) : void
public function bindValue($param, $value, int $type = ParameterType::STRING): void
{
$this->bindParam($param, $value, $type);
}
public function closeCursor() : void
{
sasql_stmt_reset($this->stmt);
}
public function columnCount() : int
{
return sasql_stmt_field_count($this->stmt);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
public function execute(?array $params = null) : void
public function execute(?array $params = null): ResultInterface
{
if ($params !== null) {
$hasZeroIndex = array_key_exists(0, $params);
......@@ -143,77 +124,6 @@ final class SQLAnywhereStatement implements Statement
throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
}
$this->result = sasql_stmt_result_metadata($this->stmt);
}
/**
* {@inheritdoc}
*
* @throws SQLAnywhereException
*/
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<int,array<int,mixed>>
*
* @throws DriverException
*/
public function fetchAllNumeric() : array
{
return FetchUtils::fetchAllNumeric($this);
}
/**
* @return array<int,array<string,mixed>>
*
* @throws DriverException
*/
public function fetchAllAssociative() : array
{
return FetchUtils::fetchAllAssociative($this);
}
/**
* @return array<int,mixed>
*
* @throws DriverException
*/
public function fetchColumn() : array
{
return FetchUtils::fetchColumn($this);
}
public function rowCount() : int
{
return sasql_stmt_affected_rows($this->stmt);
return new Result($this->stmt);
}
}
......@@ -20,7 +20,7 @@ final class Driver extends AbstractSQLServerDriver
string $username = '',
string $password = '',
array $driverOptions = []
) : Connection {
): Connection {
if (! isset($params['host'])) {
throw new SQLSrvException('Missing "host" in configuration for sqlsrv driver.');
}
......
......@@ -12,12 +12,12 @@ class LastInsertId
/** @var string|null */
private $id;
public function setId(?string $id) : void
public function setId(?string $id): void
{
$this->id = $id;
}
public function getId() : ?string
public function getId(): ?string
{
return $this->id;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -5,8 +5,10 @@ declare(strict_types=1);
namespace Doctrine\DBAL\Driver\SQLSrv;
use Doctrine\DBAL\Driver\AbstractDriverException;
use function rtrim;
use function sqlsrv_errors;
use const SQLSRV_ERR_ERRORS;
/**
......@@ -17,7 +19,7 @@ class SQLSrvException extends AbstractDriverException
/**
* Helper method to turn sql server errors into exception.
*/
public static function fromSqlSrvErrors() : self
public static function fromSqlSrvErrors(): self
{
$message = '';
$sqlState = null;
......
This diff is collapsed.
......@@ -12,5 +12,5 @@ interface ServerInfoAwareConnection extends Connection
/**
* Returns the version number of the database server connected to.
*/
public function getServerVersion() : string;
public function getServerVersion(): string;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment