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

ensureForwardCompatibilityStatement expects ResultStatement, given PDOStatement #4603

Closed
mwoods-familiaris opened this issue Apr 14, 2021 · 18 comments
Milestone

Comments

@mwoods-familiaris
Copy link

Bug Report

TypeError: Argument 1 passed to Doctrine\DBAL\Connection::ensureForwardCompatibilityStatement() must be an instance of Doctrine\DBAL\Driver\ResultStatement, instance of PDOStatement given, called in ./vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php on line 1313

Q A
BC Break yes
Version 2.13.0

Summary

executeQuery in Connection.php obtains the statement via:

$stmt = $connection->prepare($sql);

link

which is used in a forward compatibility check, added in this release:

return $this->ensureForwardCompatibilityStatement($stmt);

link

However, ensureForwardCompatibilityStatement expects $stmt to be an instance of ResultStatement, however in the case of a PDO connection, a PDOStatement is returned instead, hence the type error.

    /**
     * @param string          $sql
     * @param array<int, int> $driverOptions
     *
     * @return PDOStatement
     */
    public function prepare($sql, $driverOptions = [])
    {
        try {
            $statement = parent::prepare($sql, $driverOptions);
            assert($statement instanceof PDOStatement);

            return $statement;
        } catch (PDOException $exception) {
            throw Exception::new($exception);
        }
    }

link

How to reproduce

Execute a parameterized query using a PDO connection.

Expected behaviour

ensureForwardCompatibilityStatement parameter type should cater to all possible statement types.

@glensc
Copy link
Contributor

glensc commented Apr 14, 2021

I have a similar error when using debugbar:

Argument 1 passed to Doctrine\DBAL\Connection::ensureForwardCompatibilityStatement() must implement interface Doctrine\DBAL\Driver\ResultStatement, instance of DebugBar\DataCollector\PDO\TraceablePDOStatement given, called in /Users/glen/scm/eventum/eventum/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php on line 1315
#0 /Users/glen/scm/eventum/eventum/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(1315): Doctrine\DBAL\Connection->ensureForwardCompatibilityStatement(Object(DebugBar\DataCollector\PDO\TraceablePDOStatement))
#1 /Users/glen/scm/eventum/eventum/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php(726): Doctrine\DBAL\Connection->executeQuery('SELECT t0.upr_u...', Array, Array)
#2 /Users/glen/scm/eventum/eventum/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php(744): Doctrine\ORM\Persisters\Entity\BasicEntityPersister->load(Array, NULL)
#3 /Users/glen/scm/eventum/eventum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(472): Doctrine\ORM\Persisters\Entity\BasicEntityPersister->loadById(Array)
#4 /Users/glen/scm/eventum/eventum/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php(151): Doctrine\ORM\EntityManager->find('Eventum\\Model\\E...', Array, NULL, NULL)
#5 /Users/glen/scm/eventum/eventum/src/Model/Repository/UserPreferenceRepository.php(29): Doctrine\ORM\EntityRepository->find(2)

Integrated in two places:

@gezilixu
Copy link

I have the same error when i run php artisan migrate:generate error info: Argument 1 passed to Doctrine\DBAL\Connection::ensureForwardCompatibilityStatement() must be an instance of Doctrin
e\DBAL\Driver\ResultStatement, instance of PDOStatement given, called in myproject\ven
dor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php on line 1313, anyone konw How to solve it?

@glensc
Copy link
Contributor

glensc commented Apr 16, 2021

@gezilixu: 2.13.x is broken in certain setups (to be identified yet which), until then a workaround is to downgrade:

composer require doctrine/dbal:2.12.x

@gezilixu
Copy link

@gezilixu: 2.13.x is broken in certain setups (to be identified yet which), until then a workaround is to downgrade:

composer require doctrine/dbal:2.12.x

Wow, it worked out @glensc Thank you very much.

@mdumoulin
Copy link
Contributor

@mwoods-familiaris If I'm right, you are talking of this issue : #4564. If I'm wrong, can you provide a code sample to reproduce please.

@glensc
Copy link
Contributor

glensc commented Apr 16, 2021

Yeah, and fix seems to be in #4590

@mwoods-familiaris
Copy link
Author

@mwoods-familiaris If I'm right, you are talking of this issue : #4564. If I'm wrong, can you provide a code sample to reproduce please.

Agreed - not sure how I didn't spot that when I searched, but does appear to be the same bug.

@mdumoulin
Copy link
Contributor

mdumoulin commented Apr 16, 2021

@glensc I'm affraid that the fix here will not fully answer your expectations. If the user has already wrapped the \PDOStatement, it will be overidden in the DriverManager.
In your case, methods of class https://github.com/maximebf/php-debugbar/blob/master/src/DebugBar/DataCollector/PDO/TraceablePDOStatement.php will never be called.

<?php
require_once('vendor/autoload.php');

class MyPDOStatement extends \PDOStatement
{
    public function execute($input_parameters = null)
    {
        var_dump('Hello there');

        return parent::execute($input_parameters);
    }
}

$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_STATEMENT_CLASS, [MyPDOStatement::class, []]);

$conn = Doctrine\DBAL\DriverManager::getConnection(['pdo' => $pdo, 'driver' => 'pdo_sqlite']);
$result = $conn->executeQuery('SELECT 1;');
var_dump($result->fetchFirstColumn());

@beberlei
Copy link
Member

@mdumoulin outside of this edge case with a custom statement class, the original issue reported here was fixed by your PR #4591 or not?

@mdumoulin
Copy link
Contributor

@beberlei Yes it is fixed by #4590

@oojacoboo
Copy link

oojacoboo commented Jul 21, 2021

@mdumoulin I'm still a bit confused on all of this. 2.13 has broken our implementation and is a bit of a circular dependency for us as well. I'm getting the following error:

Argument 1 passed to Doctrine\DBAL\Connection::ensureForwardCompatibilityStatement() must be an instance of Doctrine\DBAL\Driver\ResultStatement, instance of PDOStatement given

Does Doctrine\DBAL\Connection support \PDO directly? The constructor doesn't do any validation. We have to share a PDO connection with 2 different ORMs. What's the proper way of handling this now? I can't seem to find any documentation on it. We currently have something along these lines:

$pdoConnection = PDOConnection::getInstance(); // Instance of \PDO

$dbalParams = [
    'pdo' => $pdoConnection,
];

$dbalConfig = new Configuration();

// We don't want to add any overhead on production and won't be doing any query debugging
if (!$env->isProduction()) {
    $dbalConfig->setSQLLogger(new DebugStack());
}

$connection = new DoctrineConnection($dbalParams, new MySQLDriver(), $dbalConfig); // Extended instance of Doctrine\DBAL\Connection

@mdumoulin
Copy link
Contributor

@oojacoboo You can use a PDOConnection, but the result of query execution must return a DBAL\Driver\Statement object instead of a \PDOStatement object to be compatible with DBAL.

This comment give a way of doing it : #4619 (comment)

@oojacoboo
Copy link

oojacoboo commented Jul 22, 2021

@mdumoulin I'm not using \Doctrine\DBAL\Driver\PDOConnection though. I tried to make that clear with the comments. $pdoConnection instanceof \PDO. I think you're saying you must pass a \Doctrine\DBAL\Driver\PDOConnection object to the Doctrine\DBAL\Connection constructor?

@mdumoulin
Copy link
Contributor

@oojacoboo Yes, I think, I understood. You have to make your PDO connection return a Dbal statement instead of PDOStatement when executing a query.

I haven't the full context here, but this may work for you :

<?php

use \Doctrine\DBAL\Driver\PDO\Statement as PDODriverStatement;

$pdoConnection = PDOConnection::getInstance(); // Instance of \PDO
$pdoConnection->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDODriverStatement::class, []]);

$dbalParams = [
    'pdo' => $pdoConnection,
];

$dbalConfig = new Configuration();

// We don't want to add any overhead on production and won't be doing any query debugging
if (!$env->isProduction()) {
    $dbalConfig->setSQLLogger(new DebugStack());
}

$connection = new DoctrineConnection($dbalParams, new MySQLDriver(), $dbalConfig); // Extended instance of Doctrine\DBAL\Connection

@oojacoboo
Copy link

oojacoboo commented Jul 27, 2021

@mdumoulin this results in the following error:

SQLSTATE[HY000]: General error: user-supplied statement class must be derived from PDOStatement

It might be helpful to have some boilerplate code or docs on how to use a \PDO connection with DBAL. Or maybe I missed that somewhere?

@mdumoulin
Copy link
Contributor

@oojacoboo

@mdumoulin this results in the following error:

SQLSTATE[HY000]: General error: user-supplied statement class must be derived from PDOStatement

The PDODriverStatement in my example is derived of \PDOStatement : https://github.com/doctrine/dbal/blob/2.13.x/lib/Doctrine/DBAL/Driver/PDO/Statement.php#L7

It might be helpful to have some boilerplate code or docs on how to use a \PDO connection with DBAL. Or maybe I missed that somewhere?

I can't find it either, but this feature has been removed from version 3.0. You may find some useful informations here : #3545

@jephdev
Copy link

jephdev commented Sep 6, 2021

@gezilixu: 2.13.x is broken in certain setups (to be identified yet which), until then a workaround is to downgrade:

composer require doctrine/dbal:2.12.x

I am using doctrine/dbal:2.10.2 but having the same issue when trying to run migration. How can I fix this please?

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants