Skip to content

Commit 539813d

Browse files
committed
Added transaction isolation level and access mode
1 parent 5df0e41 commit 539813d

File tree

5 files changed

+169
-41
lines changed

5 files changed

+169
-41
lines changed

ext/pdo_firebird/firebird_driver.c

Lines changed: 123 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@
2828
#include "ext/standard/info.h"
2929
#include "pdo/php_pdo.h"
3030
#include "pdo/php_pdo_driver.h"
31+
#include "pdo/php_pdo_error.h"
3132
#include "php_pdo_firebird.h"
3233
#include "php_pdo_firebird_int.h"
34+
#include "firebird_driver_arginfo.h"
3335

3436
static int firebird_alloc_prepare_stmt(pdo_dbh_t*, const zend_string*, XSQLDA*, isc_stmt_handle*, HashTable*);
3537
static bool firebird_commit_transaction(pdo_dbh_t *dbh, bool retain);
36-
static bool _firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain);
38+
static bool firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain);
3739

3840
const char CHR_LETTER = 1;
3941
const char CHR_DIGIT = 2;
@@ -480,7 +482,7 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
480482
if (dbh->auto_commit) {
481483
firebird_commit_transaction(dbh, false);
482484
} else {
483-
_firebird_rollback_transaction(dbh, false);
485+
firebird_rollback_transaction(dbh, false);
484486
}
485487
}
486488
H->in_manually_txn = 0;
@@ -702,48 +704,31 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
702704
static bool firebird_begin_transaction(pdo_dbh_t *dbh) /* {{{ */
703705
{
704706
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
705-
char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
706-
#ifdef abies_0
707-
if (dbh->transaction_flags & PDO_TRANS_ISOLATION_LEVEL) {
708-
if (dbh->transaction_flags & PDO_TRANS_READ_UNCOMMITTED) {
709-
/* this is a poor fit, but it's all we have */
707+
char tpb[5] = { isc_tpb_version3 }, *ptpb = tpb + strlen(tpb);
708+
709+
switch (H->txn_isolation_level) {
710+
case PDO_FB_READ_COMMITTED:
710711
*ptpb++ = isc_tpb_read_committed;
711712
*ptpb++ = isc_tpb_rec_version;
712-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_UNCOMMITTED);
713-
} else if (dbh->transaction_flags & PDO_TRANS_READ_COMMITTED) {
714-
*ptpb++ = isc_tpb_read_committed;
715-
*ptpb++ = isc_tpb_no_rec_version;
716-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_COMMITTED);
717-
} else if (dbh->transaction_flags & PDO_TRANS_REPEATABLE_READ) {
718-
*ptpb++ = isc_tpb_concurrency;
719-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_REPEATABLE_READ);
720-
} else {
713+
break;
714+
715+
case PDO_FB_SERIALIZABLE:
721716
*ptpb++ = isc_tpb_consistency;
722-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_SERIALIZABLE);
723-
}
724-
}
717+
break;
725718

726-
if (dbh->transaction_flags & PDO_TRANS_ACCESS_MODE) {
727-
if (dbh->transaction_flags & PDO_TRANS_READONLY) {
728-
*ptpb++ = isc_tpb_read;
729-
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
730-
} else {
731-
*ptpb++ = isc_tpb_write;
732-
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READWRITE);
733-
}
719+
case PDO_FB_REPEATABLE_READ:
720+
default:
721+
*ptpb++ = isc_tpb_concurrency;
722+
break;
734723
}
735724

736-
if (dbh->transaction_flags & PDO_TRANS_CONFLICT_RESOLUTION) {
737-
if (dbh->transaction_flags & PDO_TRANS_RETRY) {
738-
*ptpb++ = isc_tpb_wait;
739-
dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_RETRY);
740-
} else {
741-
*ptpb++ = isc_tpb_nowait;
742-
dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_ABORT);
743-
}
725+
if (H->is_writable_txn) {
726+
*ptpb++ = isc_tpb_write;
727+
} else {
728+
*ptpb++ = isc_tpb_read;
744729
}
745-
#endif
746-
if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb-tpb), tpb)) {
730+
731+
if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb - tpb), tpb)) {
747732
RECORD_ERROR(dbh);
748733
return false;
749734
}
@@ -804,8 +789,8 @@ static bool firebird_handle_manually_commit(pdo_dbh_t *dbh) /* {{{ */
804789
}
805790
/* }}} */
806791

807-
/* _firebird_rollback_transaction */
808-
static bool _firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain) /* {{{ */
792+
/* firebird_rollback_transaction */
793+
static bool firebird_rollback_transaction(pdo_dbh_t *dbh, bool retain) /* {{{ */
809794
{
810795
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
811796

@@ -830,7 +815,7 @@ static bool firebird_handle_manually_rollback(pdo_dbh_t *dbh) /* {{{ */
830815
{
831816
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
832817

833-
if (!_firebird_rollback_transaction(dbh, dbh->auto_commit)) {
818+
if (!firebird_rollback_transaction(dbh, dbh->auto_commit)) {
834819
return false;
835820
}
836821

@@ -884,6 +869,7 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
884869
{
885870
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
886871
bool bval;
872+
zend_long lval;
887873

888874
switch (attr) {
889875
case PDO_ATTR_AUTOCOMMIT:
@@ -964,6 +950,36 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
964950
zend_string_release_ex(str, 0);
965951
}
966952
return true;
953+
954+
case PDO_FB_TRANSACTION_ISOLATION_LEVEL:
955+
{
956+
if (!pdo_get_long_param(&lval, val)) {
957+
return false;
958+
}
959+
if (H->txn_isolation_level != lval) {
960+
if (lval == PDO_FB_READ_COMMITTED ||
961+
lval == PDO_FB_REPEATABLE_READ ||
962+
lval == PDO_FB_SERIALIZABLE
963+
) {
964+
if (H->tr && H->in_manually_txn) {
965+
H->last_app_error = "Cannot change isolation level while a transaction is already open";
966+
return false;
967+
}
968+
H->txn_isolation_level = lval;
969+
if (dbh->auto_commit) {
970+
if (H->tr && !firebird_commit_transaction(dbh, false)) {
971+
return false;
972+
}
973+
if (!firebird_begin_transaction(dbh)) {
974+
return false;
975+
}
976+
}
977+
} else {
978+
return false;
979+
}
980+
}
981+
}
982+
return true;
967983
}
968984
return false;
969985
}
@@ -1064,6 +1080,71 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
10641080
}
10651081
/* }}} */
10661082

1083+
/* change transaction access mode. writable or readonly */
1084+
static bool change_transaction_access_mode(pdo_dbh_t *dbh, bool writable) /* {{{ */
1085+
{
1086+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
1087+
1088+
if (H->is_writable_txn == writable) {
1089+
return true;
1090+
}
1091+
1092+
if (H->tr && H->in_manually_txn) {
1093+
H->last_app_error = "Cannot change access mode while a transaction is already open";
1094+
PDO_HANDLE_DBH_ERR();
1095+
return false;
1096+
}
1097+
H->is_writable_txn = writable;
1098+
if (dbh->auto_commit) {
1099+
if (H->tr && !firebird_commit_transaction(dbh, false)) {
1100+
return false;
1101+
}
1102+
if (!firebird_begin_transaction(dbh)) {
1103+
return false;
1104+
}
1105+
}
1106+
return true;
1107+
}
1108+
/* }}} */
1109+
1110+
/* {{{ change transaction mode to writable */
1111+
PHP_METHOD(PDO_Firebird_Ext, fbWritable)
1112+
{
1113+
pdo_dbh_t *dbh;
1114+
1115+
ZEND_PARSE_PARAMETERS_NONE();
1116+
1117+
dbh = Z_PDO_DBH_P(ZEND_THIS);
1118+
PDO_CONSTRUCT_CHECK;
1119+
1120+
RETURN_BOOL(change_transaction_access_mode(dbh, true));
1121+
}
1122+
/* }}} */
1123+
1124+
/* {{{ change transaction mode to readonly */
1125+
PHP_METHOD(PDO_Firebird_Ext, fbReadonly)
1126+
{
1127+
pdo_dbh_t *dbh;
1128+
1129+
ZEND_PARSE_PARAMETERS_NONE();
1130+
1131+
dbh = Z_PDO_DBH_P(ZEND_THIS);
1132+
PDO_CONSTRUCT_CHECK;
1133+
1134+
RETURN_BOOL(change_transaction_access_mode(dbh, false));
1135+
}
1136+
/* }}} */
1137+
1138+
static const zend_function_entry *pdo_firebird_get_driver_methods(pdo_dbh_t *dbh, int kind)
1139+
{
1140+
switch (kind) {
1141+
case PDO_DBH_DRIVER_METHOD_KIND_DBH:
1142+
return class_PDO_Firebird_Ext_methods;
1143+
default:
1144+
return NULL;
1145+
}
1146+
}
1147+
10671148
/* {{{ firebird_in_manually_transaction */
10681149
static bool firebird_in_manually_transaction(pdo_dbh_t *dbh)
10691150
{
@@ -1085,7 +1166,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10851166
pdo_firebird_fetch_error_func,
10861167
firebird_handle_get_attribute,
10871168
NULL, /* check_liveness */
1088-
NULL, /* get driver methods */
1169+
pdo_firebird_get_driver_methods,
10891170
NULL, /* request shutdown */
10901171
firebird_in_manually_transaction,
10911172
NULL /* get gc */
@@ -1169,6 +1250,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
11691250
}
11701251

11711252
H->in_manually_txn = 0;
1253+
H->is_writable_txn = 1;
11721254
if (dbh->auto_commit && !H->tr) {
11731255
ret = firebird_begin_transaction(dbh);
11741256
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
/** @generate-function-entries */
4+
5+
/**
6+
* These are extension methods for PDO. This is not a real class.
7+
* @undocumentable
8+
*/
9+
class PDO_Firebird_Ext {
10+
/** @tentative-return-type */
11+
public function fbWritable(): bool {}
12+
13+
/** @tentative-return-type */
14+
public function fbReadonly(): bool {}
15+
}

ext/pdo_firebird/firebird_driver_arginfo.h

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pdo_firebird/pdo_firebird.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ PHP_MINIT_FUNCTION(pdo_firebird) /* {{{ */
5757
REGISTER_PDO_CLASS_CONST_LONG("FB_ATTR_DATE_FORMAT", (zend_long) PDO_FB_ATTR_DATE_FORMAT);
5858
REGISTER_PDO_CLASS_CONST_LONG("FB_ATTR_TIME_FORMAT", (zend_long) PDO_FB_ATTR_TIME_FORMAT);
5959
REGISTER_PDO_CLASS_CONST_LONG("FB_ATTR_TIMESTAMP_FORMAT", (zend_long) PDO_FB_ATTR_TIMESTAMP_FORMAT);
60+
REGISTER_PDO_CLASS_CONST_LONG("FB_TRANSACTION_ISOLATION_LEVEL", (zend_long) PDO_FB_TRANSACTION_ISOLATION_LEVEL);
61+
REGISTER_PDO_CLASS_CONST_LONG("FB_READ_COMMITTED", (zend_long) PDO_FB_READ_COMMITTED);
62+
REGISTER_PDO_CLASS_CONST_LONG("FB_REPEATABLE_READ", (zend_long) PDO_FB_REPEATABLE_READ);
63+
REGISTER_PDO_CLASS_CONST_LONG("FB_SERIALIZABLE", (zend_long) PDO_FB_SERIALIZABLE);
6064

6165
if (FAILURE == php_pdo_register_driver(&pdo_firebird_driver)) {
6266
return FAILURE;

ext/pdo_firebird/php_pdo_firebird_int.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ typedef struct {
7070
/* the transaction handle */
7171
isc_tr_handle tr;
7272
bool in_manually_txn:1;
73+
bool is_writable_txn:1;
7374

7475
/* the last error that didn't come from the API */
7576
char const *last_app_error;
@@ -86,6 +87,8 @@ typedef struct {
8687

8788
unsigned _reserved:29;
8889

90+
/* transaction isolation level */
91+
zend_ulong txn_isolation_level;
8992
} pdo_firebird_db_handle;
9093

9194

@@ -132,6 +135,12 @@ enum {
132135
PDO_FB_ATTR_DATE_FORMAT = PDO_ATTR_DRIVER_SPECIFIC,
133136
PDO_FB_ATTR_TIME_FORMAT,
134137
PDO_FB_ATTR_TIMESTAMP_FORMAT,
138+
139+
/* transaction isolation level */
140+
PDO_FB_TRANSACTION_ISOLATION_LEVEL,
141+
PDO_FB_READ_COMMITTED,
142+
PDO_FB_REPEATABLE_READ,
143+
PDO_FB_SERIALIZABLE,
135144
};
136145

137146
#endif /* PHP_PDO_FIREBIRD_INT_H */

0 commit comments

Comments
 (0)