Commit ec003aad authored by Lukas Kahwe Smith's avatar Lukas Kahwe Smith Committed by Juozas Kaziukenas

initial support for settings savepoints in nested transactions

parent f1c0b3a4
......@@ -740,6 +740,23 @@ class Connection implements DriverConnection
}
}
/**
* Returns the savepoint name to use for nested transactions are false if they are not supported
* "savepointFormat" parameter is not set
*
* @return mixed a string with the savepoint name or false
*/
protected function _getNestedTransactionSavePointName($transactionNestingLevel) {
//TODO this should be configured not hardcoded, but how to do user configuration
$this->_params['savepointFormat'] = 'DOCTRINE2_SAVEPOINT_%s';
if ($this->_platform->supportsSavepoints() && !empty($this->_params['savepointFormat'])) {
return sprintf($this->_params['savepointFormat'], $this->_transactionNestingLevel);
}
return false;
}
/**
* Starts a transaction by suspending auto-commit mode.
*
......@@ -749,11 +766,16 @@ class Connection implements DriverConnection
{
$this->connect();
if ($this->_transactionNestingLevel == 0) {
++$this->_transactionNestingLevel;
if ($this->_transactionNestingLevel == 1) {
$this->_conn->beginTransaction();
} else {
$savepointName = $this->_getNestedTransactionSavePointName($this->_transactionNestingLevel);
if ($savepointName) {
$this->createSavePoint($savepointName);
}
}
++$this->_transactionNestingLevel;
}
/**
......@@ -776,6 +798,11 @@ class Connection implements DriverConnection
if ($this->_transactionNestingLevel == 1) {
$this->_conn->commit();
} else {
$savepointName = $this->_getNestedTransactionSavePointName($this->_transactionNestingLevel);
if ($savepointName) {
$this->releaseSavePoint($savepointName);
}
}
--$this->_transactionNestingLevel;
......@@ -802,11 +829,55 @@ class Connection implements DriverConnection
$this->_conn->rollback();
$this->_isRollbackOnly = false;
} else {
$this->_isRollbackOnly = true;
$savepointName = $this->_getNestedTransactionSavePointName($this->_transactionNestingLevel);
if (!$this->_isRollbackOnly && $savepointName) {
$this->rollbackSavePoint($savepointName);
} else {
$this->_isRollbackOnly = true;
}
--$this->_transactionNestingLevel;
}
}
/**
* createSavepoint
* creates a new savepoint
*
* @param string $savepoint name of a savepoint to set
* @return void
*/
public function createSavePoint($savepoint)
{
//TODO check if save points are supported? if so where?
return $this->_conn->exec($this->_platform->createSavePoint($savepoint));
}
/**
* releaseSavePoint
* releases given savepoint
*
* @param string $savepoint name of a savepoint to release
* @return void
*/
public function releaseSavePoint($savepoint)
{
//TODO check if save points are supported? if so where?
return $this->_conn->exec($this->_platform->releaseSavePoint($savepoint));
}
/**
* rollbackSavePoint
* releases given savepoint
*
* @param string $savepoint name of a savepoint to rollback to
* @return void
*/
public function rollbackSavePoint($savepoint)
{
//TODO check if save points are supported? if so where?
return $this->_conn->exec($this->_platform->rollbackSavePoint($savepoint));
}
/**
* Gets the wrapped driver connection.
*
......
......@@ -92,4 +92,46 @@ class Driver implements \Doctrine\DBAL\Driver
$params = $conn->getParams();
return $params['dbname'];
}
/**
* createSavepoint
* creates a new savepoint
*
* @param string $savepoint name of a savepoint to set
* @return void
*/
protected function createSavePoint($savepoint)
{
$query = 'SAVEPOINT ' . $savepoint;
return $this->conn->execute($query);
}
/**
* releaseSavePoint
* releases given savepoint
*
* @param string $savepoint name of a savepoint to release
* @return void
*/
protected function releaseSavePoint($savepoint)
{
$query = 'RELEASE SAVEPOINT ' . $savepoint;
return $this->conn->execute($query);
}
/**
* rollbackSavePoint
* releases given savepoint
*
* @param string $savepoint name of a savepoint to rollback to
* @return void
*/
protected function rollbackSavePoint($savepoint)
{
$query = 'ROLLBACK TO SAVEPOINT ' . $savepoint;
return $this->conn->execute($query);
}
}
\ No newline at end of file
......@@ -1986,4 +1986,37 @@ abstract class AbstractPlatform
{
return 'SELECT 1';
}
/**
* Generate SQL to create a new savepoint
*
* @param string $savepoint
* @return string
*/
public function createSavePoint($savepoint)
{
return 'SAVEPOINT ' . $savepoint;
}
/**
* Generate SQL to release a savepoint
*
* @param string $savepoint
* @return string
*/
public function releaseSavePoint($savepoint)
{
return 'RELEASE SAVEPOINT ' . $savepoint;
}
/**
* Generate SQL to rollback a savepoint
*
* @param string $savepoint
* @return string
*/
public function rollbackSavePoint($savepoint)
{
return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
}
}
\ No newline at end of file
......@@ -267,7 +267,7 @@ class MySqlPlatform extends AbstractPlatform
*/
public function supportsSavepoints()
{
return false;
return true;
}
public function getShowDatabasesSQL()
......
......@@ -43,10 +43,14 @@ class ConnectionTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
//no rethrow
}
$this->assertTrue($this->_conn->isRollbackOnly());
$this->_conn->commit(); // should throw exception
$this->fail('Transaction commit after failed nested transaction should fail.');
if ($this->_conn->getDatabasePlatform()->supportsSavepoints()) {
$this->assertFalse($this->_conn->isRollbackOnly());
} else {
$this->assertTrue($this->_conn->isRollbackOnly());
$this->_conn->commit(); // should throw exception
$this->fail('Transaction commit after failed nested transaction should fail.');
}
} catch (ConnectionException $e) {
$this->assertEquals(1, $this->_conn->getTransactionNestingLevel());
$this->_conn->rollback();
......
......@@ -125,9 +125,9 @@ class MySqlPlatformTest extends AbstractPlatformTestCase
$this->assertTrue($this->_platform->supportsIdentityColumns());
}
public function testDoesNotSupportSavePoints()
public function testDoesSupportSavePoints()
{
$this->assertFalse($this->_platform->supportsSavepoints());
$this->assertTrue($this->_platform->supportsSavepoints());
}
public function getGenerateIndexSql()
......
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