Skip to content

Commit 0765b34

Browse files
committed
[pdo_firebird] Transaction management optimization
1 parent 5c523ed commit 0765b34

12 files changed

+154
-72
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: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -526,17 +526,14 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
526526
{
527527
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
528528

529-
if (dbh->in_txn) {
529+
if (H->tr) {
530530
if (dbh->auto_commit) {
531-
if (isc_commit_transaction(H->isc_status, &H->tr)) {
532-
firebird_error(dbh);
533-
}
531+
firebird_commit_transaction(dbh, FB_TXN_RELEASE);
534532
} else {
535-
if (isc_rollback_transaction(H->isc_status, &H->tr)) {
536-
firebird_error(dbh);
537-
}
533+
firebird_rollback_transaction(dbh, FB_TXN_RELEASE);
538534
}
539535
}
536+
H->in_manually_txn = 0;
540537

541538
if (isc_detach_database(H->isc_status, &H->db)) {
542539
firebird_error(dbh);
@@ -702,9 +699,8 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /*
702699
}
703700
}
704701

705-
/* commit if we're in auto_commit mode */
706-
if (dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
707-
firebird_error(dbh);
702+
if (dbh->auto_commit && !H->in_manually_txn) {
703+
firebird_commit_transaction(dbh, FB_TXN_RETAIN);
708704
}
709705

710706
free_statement:
@@ -756,8 +752,8 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
756752
}
757753
/* }}} */
758754

759-
/* called by PDO to start a transaction */
760-
static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
755+
/* _firebird_begin_transaction */
756+
static bool _firebird_begin_transaction(pdo_dbh_t *dbh) /* {{{ */
761757
{
762758
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
763759
char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
@@ -809,28 +805,85 @@ static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
809805
}
810806
/* }}} */
811807

812-
/* called by PDO to commit a transaction */
813-
static bool firebird_handle_commit(pdo_dbh_t *dbh) /* {{{ */
808+
/* called by PDO to start a transaction */
809+
static bool firebird_handle_manually_begin(pdo_dbh_t *dbh) /* {{{ */
814810
{
815811
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
816812

817-
if (isc_commit_transaction(H->isc_status, &H->tr)) {
818-
firebird_error(dbh);
813+
if (dbh->auto_commit && H->tr && !firebird_commit_transaction(dbh, FB_TXN_RELEASE)) {
814+
return false;
815+
}
816+
817+
if (!_firebird_begin_transaction(dbh)) {
819818
return false;
820819
}
820+
821+
H->in_manually_txn = 1;
822+
return true;
823+
}
824+
/* }}} */
825+
826+
/* firebird_commit_transaction */
827+
bool _firebird_commit_transaction(pdo_dbh_t *dbh, bool retain) /* {{{ */
828+
{
829+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
830+
831+
if (retain) {
832+
if (isc_commit_retaining(H->isc_status, &H->tr)) {
833+
firebird_error(dbh);
834+
return false;
835+
}
836+
} else {
837+
if (isc_commit_transaction(H->isc_status, &H->tr)) {
838+
firebird_error(dbh);
839+
return false;
840+
}
841+
}
842+
return true;
843+
}
844+
/* }}} */
845+
846+
/* called by PDO to commit a transaction */
847+
static bool firebird_handle_manually_commit(pdo_dbh_t *dbh) /* {{{ */
848+
{
849+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
850+
if (!firebird_commit_transaction(dbh, dbh->auto_commit)) {
851+
return false;
852+
}
853+
H->in_manually_txn = 0;
854+
return true;
855+
}
856+
/* }}} */
857+
858+
/* firebird_rollback_transaction */
859+
bool _firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain) /* {{{ */
860+
{
861+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
862+
863+
if (retain) {
864+
if (isc_rollback_retaining(H->isc_status, &H->tr)) {
865+
firebird_error(dbh);
866+
return false;
867+
}
868+
} else {
869+
if (isc_rollback_transaction(H->isc_status, &H->tr)) {
870+
firebird_error(dbh);
871+
return false;
872+
}
873+
}
821874
return true;
822875
}
823876
/* }}} */
824877

825878
/* called by PDO to rollback a transaction */
826-
static bool firebird_handle_rollback(pdo_dbh_t *dbh) /* {{{ */
879+
static bool firebird_handle_manually_rollback(pdo_dbh_t *dbh) /* {{{ */
827880
{
828881
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
829882

830-
if (isc_rollback_transaction(H->isc_status, &H->tr)) {
831-
firebird_error(dbh);
883+
if (!firebird_rollback_transaction(dbh, dbh->auto_commit)) {
832884
return false;
833885
}
886+
H->in_manually_txn = 0;
834887
return true;
835888
}
836889
/* }}} */
@@ -848,16 +901,6 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql,
848901
return 0;
849902
}
850903

851-
/* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
852-
if (dbh->auto_commit && !dbh->in_txn) {
853-
/* dbh->transaction_flags = PDO_TRANS_READ_UNCOMMITTED; */
854-
855-
if (!firebird_handle_begin(dbh)) {
856-
return 0;
857-
}
858-
dbh->in_txn = true;
859-
}
860-
861904
/* allocate the statement */
862905
if (isc_dsql_allocate_statement(H->isc_status, &H->db, s)) {
863906
firebird_error(dbh);
@@ -900,19 +943,21 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
900943

901944
/* ignore if the new value equals the old one */
902945
if (dbh->auto_commit ^ bval) {
903-
if (dbh->in_txn) {
904-
if (bval) {
946+
if (bval) {
947+
if (H->in_manually_txn) {
905948
/* turning on auto_commit with an open transaction is illegal, because
906949
we won't know what to do with it */
907950
const char *msg = "Cannot enable auto-commit while a transaction is already open";
908951
firebird_error_with_info(dbh, "HY000", strlen("HY000"), msg, strlen(msg));
909952
return false;
910-
} else {
911-
/* close the transaction */
912-
if (!firebird_handle_commit(dbh)) {
913-
break;
914-
}
915-
dbh->in_txn = false;
953+
}
954+
if (!H->tr && !_firebird_begin_transaction(dbh)) {
955+
return false;
956+
}
957+
} else {
958+
/* close the transaction */
959+
if (!H->in_manually_txn && H->tr && !firebird_commit_transaction(dbh, FB_TXN_RELEASE)) {
960+
return false;
916961
}
917962
}
918963
dbh->auto_commit = bval;
@@ -1058,22 +1103,30 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
10581103
}
10591104
/* }}} */
10601105

1106+
/* {{{ firebird_in_manually_transaction */
1107+
static bool firebird_in_manually_transaction(pdo_dbh_t *dbh)
1108+
{
1109+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
1110+
return H->in_manually_txn;
1111+
}
1112+
/* }}} */
1113+
10611114
static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10621115
firebird_handle_closer,
10631116
firebird_handle_preparer,
10641117
firebird_handle_doer,
10651118
firebird_handle_quoter,
1066-
firebird_handle_begin,
1067-
firebird_handle_commit,
1068-
firebird_handle_rollback,
1119+
firebird_handle_manually_begin,
1120+
firebird_handle_manually_commit,
1121+
firebird_handle_manually_rollback,
10691122
firebird_handle_set_attribute,
10701123
NULL, /* last_id not supported */
10711124
pdo_firebird_fetch_error_func,
10721125
firebird_handle_get_attribute,
10731126
NULL, /* check_liveness */
10741127
NULL, /* get driver methods */
10751128
NULL, /* request shutdown */
1076-
NULL, /* in transaction, use PDO's internal tracking mechanism */
1129+
firebird_in_manually_transaction,
10771130
NULL /* get gc */
10781131
};
10791132
/* }}} */
@@ -1154,6 +1207,11 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
11541207
"HY000", H->isc_status[1], errmsg);
11551208
}
11561209

1210+
H->in_manually_txn = 0;
1211+
if (dbh->auto_commit && !H->tr) {
1212+
ret = _firebird_begin_transaction(dbh);
1213+
}
1214+
11571215
if (!ret) {
11581216
firebird_handle_closer(dbh);
11591217
}

ext/pdo_firebird/firebird_statement.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ static int firebird_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
180180
;
181181
}
182182

183-
/* commit? */
184-
if (stmt->dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
183+
if (stmt->dbh->auto_commit && !S->H->in_manually_txn && !firebird_commit_transaction(stmt->dbh, FB_TXN_RETAIN)) {
185184
break;
186185
}
187186

ext/pdo_firebird/php_pdo_firebird_int.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,12 @@ typedef struct {
6666
} pdo_firebird_error_info;
6767

6868
typedef struct {
69-
7069
/* the result of the last API call */
7170
ISC_STATUS isc_status[20];
7271

7372
/* the connection handle */
7473
isc_db_handle db;
7574

76-
/* the transaction handle */
77-
isc_tr_handle tr;
78-
7975
/* date and time format strings, can be set by the set_attribute method */
8076
char *date_format;
8177
char *time_format;
@@ -89,11 +85,14 @@ typedef struct {
8985
unsigned _reserved:29;
9086

9187
pdo_firebird_error_info einfo;
88+
89+
/* the transaction handle */
90+
isc_tr_handle tr;
91+
bool in_manually_txn:1;
9292
} pdo_firebird_db_handle;
9393

9494

9595
typedef struct {
96-
9796
/* the link that owns this statement */
9897
pdo_firebird_db_handle *H;
9998

@@ -136,6 +135,15 @@ extern void _firebird_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *state,
136135
#define firebird_error_with_info(d,e,el,m,ml) _firebird_error(d, NULL, e, el, m, ml)
137136
#define firebird_error_stmt_with_info(s,e,el,m,ml) _firebird_error(s->dbh, s, e, el, m, ml)
138137

138+
#define FB_TXN_RETAIN 1
139+
#define FB_TXN_RELEASE 0
140+
141+
extern bool _firebird_commit_transaction(pdo_dbh_t *dbh, bool retain);
142+
#define firebird_commit_transaction(d,r) _firebird_commit_transaction(d, r)
143+
144+
extern bool _firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain);
145+
#define firebird_rollback_transaction(d,r) _firebird_rollback_transaction(d, r)
146+
139147
enum {
140148
PDO_FB_ATTR_DATE_FORMAT = PDO_ATTR_DRIVER_SPECIFIC,
141149
PDO_FB_ATTR_TIME_FORMAT,

ext/pdo_firebird/tests/bug_47415.phpt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
1616
$dbh->exec('CREATE TABLE test47415 (idx int NOT NULL PRIMARY KEY, txt VARCHAR(20))');
1717
$dbh->exec('INSERT INTO test47415 VALUES(0, \'String0\')');
1818

19-
$dbh->commit();
20-
2119
$query = "SELECT idx, txt FROM test47415 ORDER by idx";
2220
$idx = $txt = 0;
2321
$stmt = $dbh->prepare($query);
@@ -32,8 +30,6 @@ var_dump($stmt->rowCount());
3230
$stmt = $dbh->prepare('DELETE FROM test47415');
3331
$stmt->execute();
3432

35-
$dbh->commit();
36-
3733
unset($stmt);
3834
unset($dbh);
3935
?>

ext/pdo_firebird/tests/bug_48877.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ $dbh->exec('CREATE TABLE test48877 (A integer)');
1818
$dbh->exec("INSERT INTO test48877 VALUES ('1')");
1919
$dbh->exec("INSERT INTO test48877 VALUES ('2')");
2020
$dbh->exec("INSERT INTO test48877 VALUES ('3')");
21-
$dbh->commit();
2221

2322
$query = "SELECT * FROM test48877 WHERE A = :paramno";
2423

@@ -33,7 +32,6 @@ var_dump($stmt->rowCount());
3332
$stmt = $dbh->prepare('DELETE FROM test48877');
3433
$stmt->execute();
3534

36-
$dbh->commit();
3735
unset($stmt);
3836
unset($dbh);
3937

ext/pdo_firebird/tests/bug_53280.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ require("testdb.inc");
1414

1515
$dbh->exec('CREATE TABLE test53280(A VARCHAR(30), B VARCHAR(30), C VARCHAR(30))');
1616
$dbh->exec("INSERT INTO test53280 VALUES ('A', 'B', 'C')");
17-
$dbh->commit();
1817

1918
$stmt1 = "SELECT B FROM test53280 WHERE A = ? AND B = ?";
2019
$stmt2 = "SELECT B, C FROM test53280 WHERE A = ? AND B = ?";
@@ -29,7 +28,6 @@ $stmth1->execute(array('A', 'B'));
2928
$rows = $stmth1->fetchAll(); // <------- segfault
3029
var_dump($rows);
3130

32-
$dbh->commit();
3331
unset($stmth1);
3432
unset($stmth2);
3533
unset($stmt);

ext/pdo_firebird/tests/bug_62024.phpt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ require("testdb.inc");
1515
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
1616
$dbh->exec("CREATE TABLE test62024 (ID INTEGER NOT NULL, TEXT VARCHAR(10))");
1717

18-
$dbh->commit();
19-
2018
//start actual test
2119

2220
$sql = "insert into test62024 (id, text) values (?, ?)";
@@ -31,15 +29,11 @@ var_dump($res);
3129
$res = $sttmt->execute($args_err);
3230
var_dump($res);
3331

34-
$dbh->commit();
35-
3632

3733
//teardown test data
3834
$sttmt = $dbh->prepare('DELETE FROM test62024');
3935
$sttmt->execute();
4036

41-
$dbh->commit();
42-
4337
unset($sttmt);
4438
unset($dbh);
4539

ext/pdo_firebird/tests/bug_64037.phpt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ $dbh->exec("INSERT INTO test64037 (ID, TEXT, COST) VALUES (1, 'test', -1.0)");
1818
$dbh->exec("INSERT INTO test64037 (ID, TEXT, COST) VALUES (2, 'test', -0.99)");
1919
$dbh->exec("INSERT INTO test64037 (ID, TEXT, COST) VALUES (3, 'test', -1.01)");
2020

21-
$dbh->commit();
22-
2321
$query = "SELECT * from test64037 order by ID";
2422
$stmt = $dbh->prepare($query);
2523
$stmt->execute();
@@ -32,8 +30,6 @@ var_dump($rows[2]['COST']);
3230
$stmt = $dbh->prepare('DELETE FROM test64037');
3331
$stmt->execute();
3432

35-
$dbh->commit();
36-
3733
unset($stmt);
3834
unset($dbh);
3935

0 commit comments

Comments
 (0)