Skip to content

Commit ee61562

Browse files
committed
Fix inconsistency in PDO transaction state
1 parent 87d2bb7 commit ee61562

File tree

4 files changed

+45
-17
lines changed

4 files changed

+45
-17
lines changed

ext/pdo/pdo_dbh.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,14 @@ PHP_METHOD(PDO, prepare)
577577
}
578578
/* }}} */
579579

580+
581+
static zend_bool pdo_is_in_transaction(pdo_dbh_t *dbh) {
582+
if (dbh->methods->in_transaction) {
583+
return dbh->methods->in_transaction(dbh);
584+
}
585+
return dbh->in_txn;
586+
}
587+
580588
/* {{{ Initiates a transaction */
581589
PHP_METHOD(PDO, beginTransaction)
582590
{
@@ -586,7 +594,7 @@ PHP_METHOD(PDO, beginTransaction)
586594

587595
PDO_CONSTRUCT_CHECK;
588596

589-
if (dbh->in_txn) {
597+
if (pdo_is_in_transaction(dbh)) {
590598
zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is already an active transaction");
591599
RETURN_THROWS();
592600
}
@@ -617,7 +625,7 @@ PHP_METHOD(PDO, commit)
617625

618626
PDO_CONSTRUCT_CHECK;
619627

620-
if (!dbh->in_txn) {
628+
if (!pdo_is_in_transaction(dbh)) {
621629
zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
622630
RETURN_THROWS();
623631
}
@@ -641,7 +649,7 @@ PHP_METHOD(PDO, rollBack)
641649

642650
PDO_CONSTRUCT_CHECK;
643651

644-
if (!dbh->in_txn) {
652+
if (!pdo_is_in_transaction(dbh)) {
645653
zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
646654
RETURN_THROWS();
647655
}
@@ -665,11 +673,7 @@ PHP_METHOD(PDO, inTransaction)
665673

666674
PDO_CONSTRUCT_CHECK;
667675

668-
if (!dbh->methods->in_transaction) {
669-
RETURN_BOOL(dbh->in_txn);
670-
}
671-
672-
RETURN_BOOL(dbh->methods->in_transaction(dbh));
676+
RETURN_BOOL(pdo_is_in_transaction(dbh));
673677
}
674678
/* }}} */
675679

ext/pdo_mysql/tests/pdo_mysql_commit.phpt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
2323
// DDL will issue an implicit commit
2424
$db->exec(sprintf('DROP TABLE IF EXISTS test_commit'));
2525
$db->exec(sprintf('CREATE TABLE test_commit(id INT) ENGINE=%s', MySQLPDOTest::detect_transactional_mysql_engine($db)));
26-
if (true !== ($tmp = $db->commit())) {
27-
printf("[002] No commit allowed? [%s] %s\n",
28-
$db->errorCode(), implode(' ', $db->errorInfo()));
26+
try {
27+
$db->commit();
28+
$failed = false;
29+
} catch (PDOException $e) {
30+
$failed = true;
31+
}
32+
if (!$failed) {
33+
printf("[002] Commit should have failed\n");
2934
}
3035

3136
// pdo_transaction_transitions should check this as well...

ext/pdo_mysql/tests/pdo_mysql_inTransaction.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ for ($b = 0; $b < count(BEGIN); $b++) {
3838
}
3939
}
4040
}
41+
echo "\n";
42+
43+
// DDL query causes an implicit commit.
44+
$db->beginTransaction();
45+
var_dump($db->inTransaction());
46+
$db->exec('DROP TABLE IF EXISTS test');
47+
var_dump($db->inTransaction());
48+
49+
// We should be able to start a new transaction after the implicit commit.
50+
$db->beginTransaction();
51+
var_dump($db->inTransaction());
52+
$db->commit();
4153

4254
?>
4355
--EXPECT--
@@ -65,3 +77,7 @@ bool(true)
6577
bool(false)
6678
bool(true)
6779
bool(false)
80+
81+
bool(true)
82+
bool(false)
83+
bool(true)

ext/pdo_mysql/tests/pdo_mysql_rollback.phpt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,15 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
3737
$db->query('DROP TABLE IF EXISTS test2');
3838
$db->query('CREATE TABLE test2(id INT)');
3939
$num++;
40-
$db->rollBack();
41-
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
42-
if ($row['_num'] != $num)
43-
printf("[002] ROLLBACK should have no effect because of the implicit COMMIT
44-
triggered by DROP/CREATE TABLE\n");
45-
40+
try {
41+
$db->rollBack();
42+
$failed = false;
43+
} catch (PDOException $e) {
44+
$failed = true;
45+
}
46+
if (!$failed) {
47+
printf("[003] Rollback should have failed\n");
48+
}
4649

4750
$db->query('DROP TABLE IF EXISTS test2');
4851
$db->query('CREATE TABLE test2(id INT) ENGINE=MyISAM');

0 commit comments

Comments
 (0)