Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace forward-compatible ResultStatement interfaces with Result #4049

Merged
merged 5 commits into from
Jun 7, 2020

Conversation

morozov
Copy link
Member

@morozov morozov commented Jun 6, 2020

Q A
Type deprecation
BC Break no

This patch backports the interfaces being introduced in #4045. Unfortunately, since Statement::execute() already returns bool there's no way to implement a forward-compatible behavior.

Before:

$statement->closeCursor();

After:

$statement->free();

@greg0ire
Copy link
Member

greg0ire commented Jun 6, 2020

Unfortunately, since Statement::execute() already returns bool there's no way to implement a forward-compatible behavior.

Sounds indeed complicated, maybe @derrabus would have an idea?

Only ugly solutions come to mind:

  • relying on state (some global constant, or some local property)
  • supporting an extra argument to specify you want the new behavior
  • renaming the method

@derrabus
Copy link
Member

derrabus commented Jun 6, 2020

Thank you for the ping. Splitting statement and result into different classes is a reasonable change. Thanks again for working on this.

So the question is, how to deal with the changed return type of Statement::execute()? It would be great if we could craft a forward-compatible solution here.

Only ugly solutions come to mind:

  • relying on state (some global constant, or some local property)

  • supporting an extra argument to specify you want the new behavior

  • renaming the method

All three would probably work. Right now, I would be in favor of version 2.

Another idea could be that Connection::prepare() is replaced by a new method that returns a statement with the new behavior. (Not a suggestion, just brainstorming)

I could offer to work on forward-compatible behavior for execute() once this PR is merged.

@derrabus
Copy link
Member

derrabus commented Jun 6, 2020

Would it make sense to backport the new result classes from #4045 as well, so that the old statement classes would act as proxies to the new result classes for all functionality that has been moved?

@morozov
Copy link
Member Author

morozov commented Jun 6, 2020

So the question is, how to deal with the changed return type of Statement::execute()? It would be great if we could craft a forward-compatible solution here.

Could you provide a real example of the boolean return value of execute() being used by the caller? As far as I can tell, it's a rudiment that exists because DBAL extends the PDO APIs, but the boolean return value is only meant to be used with PDO::ERRMODE_WARNING which is not the case for DBAL. The failure to execute a statement is in fact reported by throwing an exception:

$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

@morozov
Copy link
Member Author

morozov commented Jun 6, 2020

Would it make sense to backport the new result classes from #4045 as well, so that the old statement classes would act as proxies to the new result classes for all functionality that has been moved?

This was the original intent but given that we cannot return the result from execute(), what's the point of changing statement implementations? Right now, the statement itself implements the Result interface, so the consuming code can be changed to expect this type instead of the old one.

@derrabus
Copy link
Member

derrabus commented Jun 6, 2020

Could you provide a real example of the boolean return value of execute() being used by the caller?

In a pure DBAL environment, it is pointless to check for the return value because, as you pointed out, true is the only value to expect here.

However, I could imagine cases where the connection is passed to some library functionality that operates on generic PDO connections and thus needs to handle cases where PDO::ATTR_ERRMODE is not set to PDO::ERRMODE_EXCEPTION.

That code would probably look like this:

if (!$someStatement->execute($someParams)) {
    // Do some error handling.
}

That code would still work even if execute() would suddenly return an object. A piece of code that would break would be this one:

if (true !== $someStatement->execute($someParams)) {
    // Do some error handling.
}

I wouldn't write that kind of code, but I've seen projects where this was considered best practice. I expect the impact of the return type change to be pretty low, if that was the answer you're looking for. Yet, it's a breaking change.

@derrabus
Copy link
Member

derrabus commented Jun 6, 2020

Would it make sense to backport the new result classes from #4045 as well, so that the old statement classes would act as proxies to the new result classes for all functionality that has been moved?

This was the original intent but given that we cannot return the result from execute(), what's the point of changing statement implementations?

You're right, you wouldn't gain much. My strongest argument would be that you'd keep the diff between 2.11 and 3.0 smaller which could be helpful for the maintenance later on.

@morozov
Copy link
Member Author

morozov commented Jun 6, 2020

My strongest argument would be that you'd keep the diff between 2.11 and 3.0 smaller which could be helpful for the maintenance later on.

To me, it looks like too much effort for such little gain.

Let's take the driver-level statement and result as an example. Since the new Result interface implements only part of the result-related Statement interface (e.g. the result doesn't implement fetching in the mixed mode), the proxy will have to either emulate it on top of the Result API or implement it itself. The latter will require sharing the underlying statement resource between the result and the proxy.

In the case of the wrapper-level, it's even more complicated: the wrapper statement wraps a driver-level statement that may or may not implement the new interface. In this case, proxying to the Result is only possible if the wrapped statement implements Result and the method being called is part of the Result interface. Otherwise, see above.

This is the primary reason I decided to not provide FC layer for the ArrayResult and CachingResult but instead mark them internal.

@morozov
Copy link
Member Author

morozov commented Jun 6, 2020

However, I could imagine cases where the connection is passed to some library functionality that operates on generic PDO connections and thus needs to handle cases where PDO::ATTR_ERRMODE is not set to PDO::ERRMODE_EXCEPTION.

This doesn't look like a valid case. The fact that a library does if (true !== $stmt->execute()) means that it expects a non-true value to be returned in the case of an error but it will get an exception from DBAL.

I expect the impact of the return type change to be pretty low, if that was the answer you're looking for. Yet, it's a breaking change.

I totally agree. Not sure how we got into this argument. We're not going to change the return value in 2.x for the sake of providing an FC layer.

@morozov morozov requested a review from greg0ire June 7, 2020 14:48
@derrabus
Copy link
Member

derrabus commented Jun 7, 2020

This doesn't look like a valid case. The fact that a library does if (true !== $stmt->execute()) means that it expects a non-true value to be returned in the case of an error but it will get an exception from DBAL.

Yes, but you won't necessarily get an exception from PDO. This is why code like this might be in place in libraries that are not aware of DBAL and operate on generic PDO connections.

It's still not good code and it might be an edge-case. But it's the best example I could come up with.

@codecov-commenter
Copy link

codecov-commenter commented Jun 7, 2020

Codecov Report

Merging #4049 into 2.11.x will decrease coverage by 2.13%.
The diff coverage is 40.40%.

Impacted file tree graph

@@             Coverage Diff              @@
##             2.11.x    #4049      +/-   ##
============================================
- Coverage     73.16%   71.02%   -2.14%     
- Complexity     5031     5261     +230     
============================================
  Files           215      217       +2     
  Lines         12825    13355     +530     
============================================
+ Hits           9383     9485     +102     
- Misses         3442     3870     +428     
Impacted Files Coverage Δ Complexity Δ
lib/Doctrine/DBAL/Cache/ArrayStatement.php 48.52% <0.00%> (-39.28%) 30.00 <12.00> (+12.00) ⬇️
lib/Doctrine/DBAL/Cache/QueryCacheProfile.php 71.42% <ø> (ø) 11.00 <0.00> (ø)
...octrine/DBAL/Connections/MasterSlaveConnection.php 66.97% <ø> (ø) 42.00 <0.00> (ø)
.../Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php 96.36% <ø> (-1.82%) 24.00 <0.00> (ø)
...octrine/DBAL/Driver/DrizzlePDOMySql/Connection.php 0.00% <ø> (ø) 3.00 <0.00> (ø)
...ib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php 66.66% <ø> (-6.07%) 5.00 <0.00> (ø)
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php 45.74% <ø> (ø) 21.00 <0.00> (ø)
lib/Doctrine/DBAL/Driver/OCI8/Driver.php 14.28% <ø> (ø) 4.00 <0.00> (ø)
lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php 0.00% <ø> (ø) 26.00 <0.00> (ø)
lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php 22.22% <0.00%> (-3.73%) 68.00 <15.00> (+11.00) ⬇️
... and 149 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ecff851...e7c7cb1. Read the comment docs.

@morozov morozov merged commit 3cfb57d into doctrine:2.11.x Jun 7, 2020
@morozov morozov deleted the result branch June 7, 2020 16:56
@morozov morozov added this to the 2.11.0 milestone Jun 7, 2020
@morozov morozov self-assigned this Jun 7, 2020
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 7, 2021
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 7, 2021
rgrellmann added a commit to Rossmann-IT/dbal that referenced this pull request Mar 7, 2021
Release [2.11.0](https://github.com/doctrine/dbal/milestone/77)

2.11.0
======

- Total issues resolved: **7**
- Total pull requests resolved: **55**
- Total contributors: **8**

Improvement,Prepared Statements,SQL Server,Types,pdo_sqlsrv,sqlsrv
------------------------------------------------------------------

 - [4274: Support ASCII parameter binding](doctrine#4274) thanks to @gjdanis

Documentation
-------------

 - [4271: Add explanation about implicit indexes](doctrine#4271) thanks to @greg0ire

Deprecation,Error Handling
--------------------------

 - [4253: Deprecate DBAL\DBALException in favor of DBAL\Exception](doctrine#4253) thanks to @morozov

CI
--

 - [4251: Setup automatic release workflow](doctrine#4251) thanks to @greg0ire

Deprecation,Schema Managers
---------------------------

 - [4230: Deprecate the functionality of dropping client connections when dropping a database](doctrine#4230) thanks to @morozov

Deprecation,Platforms
---------------------

 - [4229: Deprecate more AbstractPlatform methods](doctrine#4229) thanks to @morozov
 - [4132: Deprecate AbstractPlatform::fixSchemaElementName()](doctrine#4132) thanks to @morozov

Improvement,Test Suite
----------------------

 - [4215: Remove test group configuration leftovers](doctrine#4215) thanks to @morozov
 - [4080: Update PHPUnit to 9.2](doctrine#4080) thanks to @morozov
 - [4079: Forward compatibility with PHPUnit 9.3](doctrine#4079) thanks to @morozov
 - [3923: Removed performance tests](doctrine#3923) thanks to @morozov

Deprecation,Schema
------------------

 - [4213: Deprecate the Synchronizer package](doctrine#4213) thanks to @morozov

Blocker,Improvement,PHP,Test Suite
----------------------------------

 - [4201: Update PHPUnit to 9.3](doctrine#4201) thanks to @morozov

Blocker,PHP,Test Suite
----------------------

 - [4196: The test suite uses the deprecated at() matcher](doctrine#4196) thanks to @morozov

Connections,Deprecation,Documentation
-------------------------------------

 - [4175: Additional deprecation note for PrimaryReplicaConnection::query()](doctrine#4175) thanks to @morozov

Connections,Deprecation,Prepared Statements
-------------------------------------------

 - [4165: Deprecated usage of wrapper components as implementations of driver-level interfaces](doctrine#4165) thanks to @morozov
 - [4020: Deprecated Connection::project(), Statement::errorCode() and errorInfo()](doctrine#4020) thanks to @morozov

Connections,Deprecation
-----------------------

 - [4163: Deprecate duplicate and ambiguous wrapper connection methods](doctrine#4163) thanks to @morozov

Error Handling,Improvement,Types
--------------------------------

 - [4145: Add TypeRegistry constructor](doctrine#4145) thanks to @morozov

Deprecation,Drivers,Improvement,pdo_mysql,pdo_oci,pdo_pgsql,pdo_sqlite,pdo_sqlsrv
---------------------------------------------------------------------------------

 - [4144: Deprecate classes in Driver\PDO* namespaces](doctrine#4144) thanks to @morozov

Connections,Documentation,Improvement
-------------------------------------

 - [4139: Mark connection constructors internal](doctrine#4139) thanks to @morozov

Deprecation,Drivers,Error Handling
----------------------------------

 - [4137: Deprecate driver exception conversion APIs](doctrine#4137) thanks to @morozov
 - [4112: Deprecate DriverException::getErrorCode()](doctrine#4112) thanks to @morozov

Configuration,Connections,Deprecation,Error Handling
----------------------------------------------------

 - [4134: Deprecate some DBALException factory methods](doctrine#4134) thanks to @morozov

Code Style,Documentation
------------------------

 - [4133: Fix more issues introduced by the deprecation of driver classes](doctrine#4133) thanks to @morozov

BC Break,Drivers,Error Handling,pdo_sqlsrv,sqlsrv
-------------------------------------------------

 - [4131: Restore the PortWithoutHost exception parent class](doctrine#4131) thanks to @morozov

Code Style,Improvement,Static Analysis
--------------------------------------

 - [4123: Remove the no longer needed error suppressions](doctrine#4123) thanks to @morozov

Deprecation,Drivers,Error Handling,Improvement
----------------------------------------------

 - [4118: Deprecate ExceptionConverterDriver](doctrine#4118) thanks to @morozov

Bug,Connections,Improvement,Prepared Statements
-----------------------------------------------

 - [4117: Fixes for the recently introduced driver-level deprecations](doctrine#4117) thanks to @morozov

Connections,Deprecation,Platform Detection
------------------------------------------

 - [4114: Deprecate ServerInfoAwareConnection#requiresQueryForServerVersion() as an implementation detail](doctrine#4114) thanks to @morozov

Deprecation,Prepared Statements,SQL Parser,oci8
-----------------------------------------------

 - [4110: Mark non-interface OCI8 driver methods internal](doctrine#4110) thanks to @morozov

Connections,Deprecation,Drivers,Improvement,Prepared Statements
---------------------------------------------------------------

 - [4100: Deprecate inconsistently and ambiguously named driver-level classes](doctrine#4100) thanks to @morozov

Connections,Improvement
-----------------------

 - [4092: Remove Connection::$isConnected](doctrine#4092) thanks to @morozov

Configuration,Connections
-------------------------

 - [4086: Mark Connection::getParams() internal](doctrine#4086) thanks to @morozov

Bug,Drivers,ibm_db2
-------------------

 - [4085: The IBM DB2 driver Exception class must implement the DriverException interface](doctrine#4085) thanks to @morozov

PHP
---

 - [4078: Bump PHP requirement to 7.3 as of DBAL 2.11.0](doctrine#4078) thanks to @morozov

Connections,Databases,Deprecation,Drivers
-----------------------------------------

 - [4068: Deprecate Driver::getDatabase()](doctrine#4068) thanks to @morozov

Deprecation,Improvement,Portability
-----------------------------------

 - [4061: Deprecated platform-specific portability mode constants](doctrine#4061) thanks to @morozov

 - [4054: &doctrine#91;doctrineGH-4052&doctrine#93; Deprecate MasterSlaveConnection and rename to PrimaryReplicaConnection](doctrine#4054) thanks to @beberlei and @albe
 - [4017: Improve help of dbal:run-sql command](doctrine#4017) thanks to @ostrolucky

Code Style,Improvement
----------------------

 - [4050: Update doctrine/coding-standard to 8.0](doctrine#4050) thanks to @morozov

Cache,Deprecation,Improvement,Prepared Statements
-------------------------------------------------

 - [4049: Replace forward-compatible ResultStatement interfaces with Result](doctrine#4049) thanks to @morozov

Cache,Improvement,Prepared Statements
-------------------------------------

 - [4048: Make caching layer not rely on closeCursor()](doctrine#4048) thanks to @morozov

Deprecation,Improvement,Prepared Statements
-------------------------------------------

 - [4037: Introduce Statement::fetchFirstColumn()](doctrine#4037) thanks to @morozov
 - [4019: Deprecated the concept of the fetch mode](doctrine#4019) thanks to @morozov

Bug,Documentation,Improvement,Prepared Statements
-------------------------------------------------

 - [4034: Additional changes based on the discussion in doctrine#4007](doctrine#4034) thanks to @morozov

Connections,Console,Improvement
-------------------------------

 - [3956: allow using multiple connections for CLI commands](doctrine#3956) thanks to @dmaicher

Deprecation,Logging
-------------------

 - [3935: Deprecate EchoSQLLogger](doctrine#3935) thanks to @morozov

Improvement,Packaging
---------------------

 - [3924: Actualize the content of the .gitattributes file](doctrine#3924) thanks to @morozov

Azure,Deprecation,Drivers,Drizzle,MariaDB,Platforms,PostgreSQL,SQL Anywhere,SQL Server,Sharding,pdo_ibm
-------------------------------------------------------------------------------------------------------

 - [3905: Deprecate the usage of the legacy platforms and drivers](doctrine#3905) thanks to @morozov

Deprecation,Query
-----------------

 - [3864: CompositeExpression and()/or() factory methods](doctrine#3864) thanks to @BenMorel
 - [3853: Deprecate calling QueryBuilder methods with an array argument](doctrine#3853) thanks to @BenMorel and @morozov

Deprecation,Tools
-----------------

 - [3861: Deprecated the usage of the Version class](doctrine#3861) thanks to @morozov

Improvement,Query
-----------------

 - [3852: First parameter of ExpressionBuilder::and/or() mandatory](doctrine#3852) thanks to @BenMorel

Deprecation,Improvement,Query
-----------------------------

 - [3851: Rename andX() / orX() methods](doctrine#3851) thanks to @BenMorel
 - [3850: Prepare CompositeExpression for immutability](doctrine#3850) thanks to @BenMorel

# gpg: Signature made Mon Sep 21 01:47:31 2020
# gpg:                using DSA key 1BEDEE0A820BC30D858F9F0C2C3A645671828132
# gpg: Can't check signature: No public key

# Conflicts:
#	README.md
#	lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php
#	lib/Doctrine/DBAL/Driver/OCI8/Driver.php
#	lib/Doctrine/DBAL/Version.php
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 11, 2021
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 11, 2021
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 22, 2021
beberlei added a commit to beberlei/dbal that referenced this pull request Mar 27, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants