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

Merge branch '3.0.x'

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