Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 93 additions & 25 deletions core/DB/DB.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ abstract class DB
* flag to indicate whether we're in transaction
**/
private $transaction = false;
private $transactionList = array();

private $queue = array();
private $toQueue = false;
Expand Down Expand Up @@ -65,6 +66,9 @@ public function __destruct()
}
}

/**
* @return Dialect
*/
public static function getDialect()
{
throw new UnimplementedFeatureException('implement me, please');
Expand Down Expand Up @@ -111,20 +115,27 @@ public function begin(
/* AccessMode */ $mode = null
)
{
$begin = 'begin';

if ($level && $level instanceof IsolationLevel)
$begin .= ' '.$level->toString();

if ($mode && $mode instanceof AccessMode)
$begin .= ' '.$mode->toString();
if (!$this->transaction) {
$begin = 'begin';

if ($this->toQueue)
$this->queue[] = $begin;
else
$this->queryRaw("{$begin};\n");

$this->transaction = true;
if ($level && $level instanceof IsolationLevel)
$begin .= ' '.$level->toString();

if ($mode && $mode instanceof AccessMode)
$begin .= ' '.$mode->toString();

if ($this->toQueue)
$this->queue[] = $begin;
else
$this->queryRaw("{$begin};\n");

$this->transaction = true;
} else {
$deep = count($this->transactionList) + 1;
$savepointName = 'onPHP_inTransaction'.$deep;
$this->savePoint($savepointName);
array_push($this->transactionList, $savepointName);
}

return $this;
}
Expand All @@ -134,12 +145,16 @@ public function begin(
**/
public function commit()
{
if ($this->toQueue)
$this->queue[] = 'commit;';
else
$this->queryRaw("commit;\n");

$this->transaction = false;
if (empty($this->transactionList)) {
if ($this->toQueue)
$this->queue[] = 'commit;';
else
$this->queryRaw("commit;\n");
$this->transaction = false;
} else {
$savepointName = array_pop($this->transactionList);
$this->releaseSavepoint($savepointName);
}

return $this;
}
Expand All @@ -149,12 +164,17 @@ public function commit()
**/
public function rollback()
{
if ($this->toQueue)
$this->queue[] = 'rollback;';
else
$this->queryRaw("rollback;\n");

$this->transaction = false;
if (empty($this->transactionList)) {
if ($this->toQueue)
$this->queue[] = 'rollback;';
else
$this->queryRaw("rollback;\n");

$this->transaction = false;
} else {
$savepointName = array_pop($this->transactionList);
$this->rollbackToSavepoint($savepointName);
}

return $this;
}
Expand All @@ -165,6 +185,54 @@ public function inTransaction()
}
//@}

/**
* @param string $savePoint
* @return DB
**/
public function savePoint($savePoint)
{
// $savePoint = $this->getDialect()->toFieldString($savePoint);
$savepoint = "savepoint {$savePoint};";
if ($this->toQueue)
$this->queue[] = $savepoint;
else
$this->queryRaw("{$savepoint}\n");

return $this;
}

/**
* @param string $savePoint
* @return DB
**/
public function releaseSavepoint($savePoint)
{
// $savePoint = $this->getDialect()->toFieldString($savePoint);
$releaseSavepoint = "release savepoint {$savePoint};";
if ($this->toQueue)
$this->queue[] = $releaseSavepoint;
else
$this->queryRaw("{$releaseSavepoint}\n");

return $this;
}

/**
* @param string $savePoint
* @return DB
**/
public function rollbackToSavepoint($savePoint)
{
// $savePoint = $this->getDialect()->toFieldString($savePoint);
$releaseSavepoint = "rollback to savepoint {$savePoint};";
if ($this->toQueue)
$this->queue[] = $releaseSavepoint;
else
$this->queryRaw("{$releaseSavepoint}\n");

return $this;
}

/**
* queue handling
* @deprecated by Queue class
Expand Down
7 changes: 6 additions & 1 deletion core/OSQL/CreateTableQuery.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ public function toDialectString(Dialect $dialect)
}
}

return $out."\n);\n";
$out .= "\n)";
if ($dialect instanceof MyDialect) {
$out .= ' TYPE=innodb ';
}

return $out.";\n";
}
}
?>
1 change: 1 addition & 0 deletions test/AllTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public static function suite()
}

$suite->addTestSuite('DAOTest');
$suite->addTestSuite('TransactionTest');

return $suite;
}
Expand Down
140 changes: 140 additions & 0 deletions test/misc/TransactionTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php
/* $Id$ */

class TransactionTest extends TestTables
{
public function create()
{
/**
* @see testRecursionObjects() and meta
* for TestParentObject and TestChildObject
**/
$this->schema->
getTableByName('test_parent_object')->
getColumnByName('root_id')->
dropReference();

return parent::create();
}

public function testData()
{
$this->create();

foreach (DBTestPool::me()->getPool() as $connector => $db) {
DBPool::me()->setDefault($db);
$this->simpleTransaction();

$this->innerTransactions();
}

$this->drop();
}

private function simpleTransaction()
{
$idList = $this->insertAndCommit();
$idList += $this->insertAndRollback();
}

private function innerTransactions()
{
$dao = TestItem::dao();

$idList = $this->externalCommit();
$idList = $this->externalRollback();

$itemList = $dao->getListByIds($idList);
$this->assertEquals(count($idList), count($itemList));
}

/**
* @return array
**/
private function externalCommit()
{
$dao = TestItem::dao();
$db = DBPool::getByDao($dao);
$db->begin();

$idList = $this->insertAndCommit();
$idList += $this->insertAndRollback();

$db->commit();

$itemList = $dao->getListByIds($idList);
$this->assertEquals(count($idList), count($itemList));

return $idList;
}

/**
* @return array
**/
private function externalRollback()
{
$dao = TestItem::dao();
$db = DBPool::getByDao($dao);
$db->begin();

$idList = $this->insertAndCommit();
$idList += $this->insertAndRollback();

$db->rollback();
$dao->uncacheByIds($idList);

$itemList = $dao->getListByIds($idList);
$this->assertTrue(empty($itemList));

return array();
}

/**
* @return array
**/
private function insertAndCommit()
{
$dao = TestItem::dao();
$db = DBPool::getByDao($dao);
$db->begin();

$item = $dao->add(TestItem::create()->setName('someItem'));
$itemId = $item->getId();

$db->commit();

try {
$dao->getById($itemId);
} catch (ObjectNotFoundException $e) {
$this->fail('Object must be saved');
}

return array($itemId);
}

/**
* @return array
**/
private function insertAndRollback()
{
$dao = TestItem::dao();
$db = DBPool::getByDao($dao);
$db->begin();

$item = $dao->add(TestItem::create()->setName('someItem'));
$itemId = $item->getId();

$db->rollback();
$dao->uncacheById($itemId);

try {
$dao->getById($itemId);
$this->fail('Object must not be saved');
} catch (ObjectNotFoundException $e) {
/* all ok */
}

return array();
}
}
?>