Commit 7cd0589f authored by Sergei Morozov's avatar Sergei Morozov Committed by Marco Pivetta

[DBAL-2546] Reworked implementation of closeCursor() for mysqli, ibm_db2 and oci drivers

parent fc376f7a
......@@ -104,11 +104,8 @@ class DB2Statement implements \IteratorAggregate, Statement
}
$this->_bindParam = array();
db2_free_result($this->_stmt);
$ret = db2_free_stmt($this->_stmt);
$this->_stmt = false;
return $ret;
return db2_free_result($this->_stmt);
}
/**
......
......@@ -176,7 +176,13 @@ class OCI8Statement implements \IteratorAggregate, Statement
*/
public function closeCursor()
{
return oci_free_statement($this->_sth);
// emulate it by fetching and discarding rows, similarly to what PDO does in this case
// @link http://php.net/manual/en/pdostatement.closecursor.php
// @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075
// deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them
while (oci_fetch($this->_sth));
return true;
}
/**
......
......@@ -150,9 +150,13 @@ class SQLSrvStatement implements IteratorAggregate, Statement
*/
public function closeCursor()
{
if ($this->stmt) {
sqlsrv_free_stmt($this->stmt);
}
// emulate it by fetching and discarding rows, similarly to what PDO does in this case
// @link http://php.net/manual/en/pdostatement.closecursor.php
// @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075
// deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them
while (sqlsrv_fetch($this->stmt));
return true;
}
/**
......
<?php
namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\Schema\Table;
class StatementTest extends \Doctrine\Tests\DbalFunctionalTestCase
{
public function testStatementIsReusableAfterClosingCursor()
{
$sm = $this->_conn->getSchemaManager();
$table = new Table('stmt_test_reusable');
$table->addColumn('id', 'integer');
$sm->createTable($table);
$this->_conn->insert('stmt_test_reusable', array('id' => 1));
$this->_conn->insert('stmt_test_reusable', array('id' => 2));
$stmt = $this->_conn->prepare('SELECT id FROM stmt_test_reusable ORDER BY id');
$stmt->execute();
$id = $stmt->fetchColumn();
$this->assertEquals(1, $id);
$stmt->closeCursor();
$stmt->execute();
$id = $stmt->fetchColumn();
$this->assertEquals(1, $id);
$id = $stmt->fetchColumn();
$this->assertEquals(2, $id);
}
public function testClosedCursorDoesNotContainResults()
{
$sm = $this->_conn->getSchemaManager();
$table = new Table('stmt_test_no_results');
$table->addColumn('id', 'integer');
$sm->createTable($table);
$this->_conn->insert('stmt_test_no_results', array('id' => 1));
$stmt = $this->_conn->prepare('SELECT id FROM stmt_test_no_results');
$stmt->execute();
$stmt->closeCursor();
try {
$value = $stmt->fetchColumn();
} catch (\Exception $e) {
// some adapters trigger PHP error or throw adapter-specific exception in case of fetching
// from a closed cursor, which still proves that it has been closed
return;
}
$this->assertFalse($value);
}
}
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