Skip to content

Commit 58f49a3

Browse files
committed
Corrected and optimized pdo_firebird transaction handling.
1 parent 490b808 commit 58f49a3

File tree

4 files changed

+80
-35
lines changed

4 files changed

+80
-35
lines changed

ext/pdo/tests/pdo_017.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ $dir = getenv('REDIR_TEST_DIR');
88
if (false == $dir) die('skip no driver');
99
require_once $dir . 'pdo_test.inc';
1010
PDOTest::skip();
11-
if (str_starts_with(getenv('PDOTEST_DSN'), "firebird")) die('xfail firebird driver does not behave as expected');
1211

1312
$db = PDOTest::factory();
1413
try {

ext/pdo_firebird/firebird_driver.c

Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
475475
{
476476
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
477477

478-
if (dbh->in_txn) {
478+
if (H->tr) {
479479
if (dbh->auto_commit) {
480480
if (isc_commit_transaction(H->isc_status, &H->tr)) {
481481
RECORD_ERROR(dbh);
@@ -486,6 +486,7 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
486486
}
487487
}
488488
}
489+
H->in_manually_txn = 0;
489490

490491
if (isc_detach_database(H->isc_status, &H->db)) {
491492
RECORD_ERROR(dbh);
@@ -647,8 +648,10 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /*
647648
}
648649

649650
/* commit if we're in auto_commit mode */
650-
if (dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
651-
RECORD_ERROR(dbh);
651+
if (dbh->auto_commit && !H->in_manually_txn) {
652+
if (isc_commit_retaining(H->isc_status, &H->tr)) {
653+
RECORD_ERROR(dbh);
654+
}
652655
}
653656

654657
free_statement:
@@ -700,8 +703,8 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
700703
}
701704
/* }}} */
702705

703-
/* called by PDO to start a transaction */
704-
static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
706+
/* firebird_begin_transaction */
707+
static bool firebird_begin_transaction(pdo_dbh_t *dbh) /* {{{ */
705708
{
706709
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
707710
char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
@@ -753,15 +756,42 @@ static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
753756
}
754757
/* }}} */
755758

756-
/* called by PDO to commit a transaction */
757-
static bool firebird_handle_commit(pdo_dbh_t *dbh) /* {{{ */
759+
/* called by PDO to start a transaction */
760+
static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
758761
{
759762
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
760763

761-
if (isc_commit_transaction(H->isc_status, &H->tr)) {
764+
if (dbh->auto_commit && H->tr && isc_commit_transaction(H->isc_status, &H->tr)) {
762765
RECORD_ERROR(dbh);
763766
return false;
764767
}
768+
769+
if (!firebird_begin_transaction(dbh)) {
770+
return false;
771+
}
772+
773+
H->in_manually_txn = 1;
774+
return true;
775+
}
776+
/* }}} */
777+
778+
/* called by PDO to commit a transaction */
779+
static bool firebird_handle_commit(pdo_dbh_t *dbh) /* {{{ */
780+
{
781+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
782+
783+
if (dbh->auto_commit) {
784+
if (isc_commit_retaining(H->isc_status, &H->tr)) {
785+
RECORD_ERROR(dbh);
786+
return false;
787+
}
788+
} else {
789+
if (isc_commit_transaction(H->isc_status, &H->tr)) {
790+
RECORD_ERROR(dbh);
791+
return false;
792+
}
793+
}
794+
H->in_manually_txn = 0;
765795
return true;
766796
}
767797
/* }}} */
@@ -771,10 +801,18 @@ static bool firebird_handle_rollback(pdo_dbh_t *dbh) /* {{{ */
771801
{
772802
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
773803

774-
if (isc_rollback_transaction(H->isc_status, &H->tr)) {
775-
RECORD_ERROR(dbh);
776-
return false;
804+
if (dbh->auto_commit) {
805+
if (isc_rollback_retaining(H->isc_status, &H->tr)) {
806+
RECORD_ERROR(dbh);
807+
return false;
808+
}
809+
} else {
810+
if (isc_rollback_transaction(H->isc_status, &H->tr)) {
811+
RECORD_ERROR(dbh);
812+
return false;
813+
}
777814
}
815+
H->in_manually_txn = 0;
778816
return true;
779817
}
780818
/* }}} */
@@ -792,16 +830,6 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql,
792830
return 0;
793831
}
794832

795-
/* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
796-
if (dbh->auto_commit && !dbh->in_txn) {
797-
/* dbh->transaction_flags = PDO_TRANS_READ_UNCOMMITTED; */
798-
799-
if (!firebird_handle_begin(dbh)) {
800-
return 0;
801-
}
802-
dbh->in_txn = true;
803-
}
804-
805833
/* allocate the statement */
806834
if (isc_dsql_allocate_statement(H->isc_status, &H->db, s)) {
807835
RECORD_ERROR(dbh);
@@ -844,19 +872,22 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
844872

845873
/* ignore if the new value equals the old one */
846874
if (dbh->auto_commit ^ bval) {
847-
if (dbh->in_txn) {
848-
if (bval) {
875+
if (bval) {
876+
if (H->tr && H->in_manually_txn) {
849877
/* turning on auto_commit with an open transaction is illegal, because
850-
we won't know what to do with it */
878+
we won't know what to do with it */
851879
H->last_app_error = "Cannot enable auto-commit while a transaction is already open";
852880
return false;
853-
} else {
854-
/* close the transaction */
855-
if (!firebird_handle_commit(dbh)) {
856-
break;
857-
}
858-
dbh->in_txn = false;
859881
}
882+
if (!H->tr && !firebird_begin_transaction(dbh)) {
883+
return false;
884+
}
885+
} else {
886+
/* close the transaction */
887+
if (!H->tr && !firebird_handle_commit(dbh)) {
888+
return false;
889+
}
890+
H->in_manually_txn = 0;
860891
}
861892
dbh->auto_commit = bval;
862893
}
@@ -1011,6 +1042,14 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
10111042
}
10121043
/* }}} */
10131044

1045+
/* {{{ firebird_in_transaction */
1046+
static bool firebird_in_transaction(pdo_dbh_t *dbh)
1047+
{
1048+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
1049+
return H->tr && H->in_manually_txn;
1050+
}
1051+
/* }}} */
1052+
10141053
static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10151054
firebird_handle_closer,
10161055
firebird_handle_preparer,
@@ -1026,7 +1065,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10261065
NULL, /* check_liveness */
10271066
NULL, /* get driver methods */
10281067
NULL, /* request shutdown */
1029-
NULL, /* in transaction, use PDO's internal tracking mechanism */
1068+
firebird_in_transaction,
10301069
NULL /* get gc */
10311070
};
10321071
/* }}} */
@@ -1107,6 +1146,11 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
11071146
"HY000", H->isc_status[1], errmsg);
11081147
}
11091148

1149+
H->in_manually_txn = 0;
1150+
if (dbh->auto_commit && !H->tr) {
1151+
ret = firebird_begin_transaction(dbh);
1152+
}
1153+
11101154
if (!ret) {
11111155
firebird_handle_closer(dbh);
11121156
}

ext/pdo_firebird/firebird_statement.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,10 @@ static int firebird_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
177177
;
178178
}
179179

180-
/* commit? */
181-
if (stmt->dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
182-
break;
180+
if (stmt->dbh->auto_commit && !S->H->in_manually_txn) {
181+
if (isc_commit_retaining(H->isc_status, &H->tr)) {
182+
break;
183+
}
183184
}
184185

185186
*S->name = 0;

ext/pdo_firebird/php_pdo_firebird_int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ typedef struct {
6969

7070
/* the transaction handle */
7171
isc_tr_handle tr;
72+
bool in_manually_txn:1;
7273

7374
/* the last error that didn't come from the API */
7475
char const *last_app_error;

0 commit comments

Comments
 (0)