Commit 30eb6b95 authored by Danny Berger's avatar Danny Berger Committed by Benjamin Eberlei

Support OCI8 statements crossing transactions [DBAL-202]

parent 15c23239
...@@ -57,7 +57,7 @@ class OCI8Connection implements \Doctrine\DBAL\Driver\Connection ...@@ -57,7 +57,7 @@ class OCI8Connection implements \Doctrine\DBAL\Driver\Connection
*/ */
public function prepare($prepareString) public function prepare($prepareString)
{ {
return new OCI8Statement($this->_dbh, $prepareString, $this->_executeMode); return new OCI8Statement($this->_dbh, $prepareString, $this);
} }
/** /**
...@@ -107,6 +107,14 @@ class OCI8Connection implements \Doctrine\DBAL\Driver\Connection ...@@ -107,6 +107,14 @@ class OCI8Connection implements \Doctrine\DBAL\Driver\Connection
//TODO: throw exception or support sequences? //TODO: throw exception or support sequences?
} }
/**
* Return the current execution mode.
*/
public function getExecuteMode()
{
return $this->_executeMode;
}
/** /**
* Start a transactiom * Start a transactiom
* *
......
...@@ -34,7 +34,7 @@ class OCI8Statement implements \IteratorAggregate, Statement ...@@ -34,7 +34,7 @@ class OCI8Statement implements \IteratorAggregate, Statement
/** Statement handle. */ /** Statement handle. */
protected $_dbh; protected $_dbh;
protected $_sth; protected $_sth;
protected $_executeMode; protected $_conn;
protected static $_PARAM = ':param'; protected static $_PARAM = ':param';
protected static $fetchStyleMap = array( protected static $fetchStyleMap = array(
PDO::FETCH_BOTH => OCI_BOTH, PDO::FETCH_BOTH => OCI_BOTH,
...@@ -51,13 +51,13 @@ class OCI8Statement implements \IteratorAggregate, Statement ...@@ -51,13 +51,13 @@ class OCI8Statement implements \IteratorAggregate, Statement
* @param resource $dbh The connection handle. * @param resource $dbh The connection handle.
* @param string $statement The SQL statement. * @param string $statement The SQL statement.
*/ */
public function __construct($dbh, $statement, $executeMode) public function __construct($dbh, $statement, OCI8Connection $conn)
{ {
list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement); list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement);
$this->_sth = oci_parse($dbh, $statement); $this->_sth = oci_parse($dbh, $statement);
$this->_dbh = $dbh; $this->_dbh = $dbh;
$this->_paramMap = $paramMap; $this->_paramMap = $paramMap;
$this->_executeMode = $executeMode; $this->_conn = $conn;
} }
/** /**
...@@ -179,7 +179,7 @@ class OCI8Statement implements \IteratorAggregate, Statement ...@@ -179,7 +179,7 @@ class OCI8Statement implements \IteratorAggregate, Statement
} }
} }
$ret = @oci_execute($this->_sth, $this->_executeMode); $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode());
if ( ! $ret) { if ( ! $ret) {
throw OCI8Exception::fromErrorInfo($this->errorInfo()); throw OCI8Exception::fromErrorInfo($this->errorInfo());
} }
......
...@@ -15,21 +15,13 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase ...@@ -15,21 +15,13 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase
parent::setUp(); parent::setUp();
} }
protected function getMockOCI8Statement()
{
$dbh = null;
$statement = "update table set field1 = ?, field2 = ? where field3 = ?";
$executeMode = OCI_COMMIT_ON_SUCCESS;
return $this->getMock('\Doctrine\DBAL\Driver\OCI8\OCI8Statement',
array('bindValue', 'errorInfo'),
array(null, $statement, $executeMode), '', false);
}
/** /**
* This scenario shows that when the first parameter is not null * This scenario shows that when the first parameter is not null
* it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1. * it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1.
* *
* This also verifies that the statement will check with the connection to
* see what the current execution mode is.
*
* The expected exception is due to oci_execute failing due to no valid connection. * The expected exception is due to oci_execute failing due to no valid connection.
* *
* @dataProvider executeDataProvider * @dataProvider executeDataProvider
...@@ -37,7 +29,9 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase ...@@ -37,7 +29,9 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase
*/ */
public function testExecute(array $params) public function testExecute(array $params)
{ {
$statement = $this->getMockOCI8Statement(); $statement = $this->getMock('\Doctrine\DBAL\Driver\OCI8\OCI8Statement',
array('bindValue', 'errorInfo'),
array(), '', false);
$statement->expects($this->at(0)) $statement->expects($this->at(0))
->method('bindValue') ->method('bindValue')
...@@ -58,6 +52,16 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase ...@@ -58,6 +52,16 @@ class OCI8StatementTest extends \Doctrine\Tests\DbalTestCase
$this->equalTo($params[2]) $this->equalTo($params[2])
); );
// can't pass to constructor since we don't have a real database handle,
// but execute must check the connection for the executeMode
$conn = $this->getMock('\Doctrine\DBAL\Driver\OCI8\OCI8Connection', array('getExecuteMode'), array(), '', false);
$conn->expects($this->once())
->method('getExecuteMode');
$reflProperty = new \ReflectionProperty($statement, '_conn');
$reflProperty->setAccessible(true);
$reflProperty->setValue($statement, $conn);
$statement->execute($params); $statement->execute($params);
} }
......
<?php
namespace Doctrine\Tests\DBAL\Functional\Ticket;
/**
* @group DBAL-202
*/
class DBAL202Test extends \Doctrine\Tests\DbalFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
if ($this->_conn->getDatabasePlatform()->getName() != 'oracle') {
$this->markTestSkipped('OCI8 only test');
}
if ($this->_conn->getSchemaManager()->tablesExist('DBAL202')) {
$this->_conn->executeQuery('DELETE FROM DBAL202');
} else {
$table = new \Doctrine\DBAL\Schema\Table('DBAL202');
$table->addColumn('id', 'integer');
$table->setPrimaryKey(array('id'));
$this->_conn->getSchemaManager()->createTable($table);
}
}
public function testStatementRollback()
{
$stmt = $this->_conn->prepare('INSERT INTO DBAL202 VALUES (8)');
$this->_conn->beginTransaction();
$stmt->execute();
$this->_conn->rollback();
$this->assertEquals(0, $this->_conn->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn());
}
public function testStatementCommit()
{
$stmt = $this->_conn->prepare('INSERT INTO DBAL202 VALUES (8)');
$this->_conn->beginTransaction();
$stmt->execute();
$this->_conn->commit();
$this->assertEquals(1, $this->_conn->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn());
}
}
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