Skip to content

Commit 207306f

Browse files
committed
Added transaction isolation level and access mode
1 parent f0ca8ff commit 207306f

File tree

5 files changed

+157
-36
lines changed

5 files changed

+157
-36
lines changed

ext/pdo_firebird/firebird_driver.c

Lines changed: 111 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
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

@@ -700,48 +702,31 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
700702
static bool _firebird_begin_transaction(pdo_dbh_t *dbh) /* {{{ */
701703
{
702704
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
703-
char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
704-
#ifdef abies_0
705-
if (dbh->transaction_flags & PDO_TRANS_ISOLATION_LEVEL) {
706-
if (dbh->transaction_flags & PDO_TRANS_READ_UNCOMMITTED) {
707-
/* this is a poor fit, but it's all we have */
705+
char tpb[5] = { isc_tpb_version3 }, *ptpb = tpb + strlen(tpb);
706+
707+
switch (H->txn_isolation_level) {
708+
case PDO_FB_READ_COMMITTED:
708709
*ptpb++ = isc_tpb_read_committed;
709710
*ptpb++ = isc_tpb_rec_version;
710-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_UNCOMMITTED);
711-
} else if (dbh->transaction_flags & PDO_TRANS_READ_COMMITTED) {
712-
*ptpb++ = isc_tpb_read_committed;
713-
*ptpb++ = isc_tpb_no_rec_version;
714-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_COMMITTED);
715-
} else if (dbh->transaction_flags & PDO_TRANS_REPEATABLE_READ) {
716-
*ptpb++ = isc_tpb_concurrency;
717-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_REPEATABLE_READ);
718-
} else {
711+
break;
712+
713+
case PDO_FB_SERIALIZABLE:
719714
*ptpb++ = isc_tpb_consistency;
720-
dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_SERIALIZABLE);
721-
}
722-
}
715+
break;
723716

724-
if (dbh->transaction_flags & PDO_TRANS_ACCESS_MODE) {
725-
if (dbh->transaction_flags & PDO_TRANS_READONLY) {
726-
*ptpb++ = isc_tpb_read;
727-
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
728-
} else {
729-
*ptpb++ = isc_tpb_write;
730-
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READWRITE);
731-
}
717+
case PDO_FB_REPEATABLE_READ:
718+
default:
719+
*ptpb++ = isc_tpb_concurrency;
720+
break;
732721
}
733722

734-
if (dbh->transaction_flags & PDO_TRANS_CONFLICT_RESOLUTION) {
735-
if (dbh->transaction_flags & PDO_TRANS_RETRY) {
736-
*ptpb++ = isc_tpb_wait;
737-
dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_RETRY);
738-
} else {
739-
*ptpb++ = isc_tpb_nowait;
740-
dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_ABORT);
741-
}
723+
if (H->is_writable_txn) {
724+
*ptpb++ = isc_tpb_write;
725+
} else {
726+
*ptpb++ = isc_tpb_read;
742727
}
743-
#endif
744-
if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb-tpb), tpb)) {
728+
729+
if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb - tpb), tpb)) {
745730
RECORD_ERROR(dbh);
746731
return false;
747732
}
@@ -882,6 +867,7 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
882867
{
883868
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
884869
bool bval;
870+
zend_long lval;
885871

886872
switch (attr) {
887873
case PDO_ATTR_AUTOCOMMIT:
@@ -962,6 +948,36 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
962948
zend_string_release_ex(str, 0);
963949
}
964950
return true;
951+
952+
case PDO_FB_TRANSACTION_ISOLATION_LEVEL:
953+
{
954+
if (!pdo_get_long_param(&lval, val)) {
955+
return false;
956+
}
957+
if (H->txn_isolation_level != lval) {
958+
if (lval == PDO_FB_READ_COMMITTED ||
959+
lval == PDO_FB_REPEATABLE_READ ||
960+
lval == PDO_FB_SERIALIZABLE
961+
) {
962+
if (H->tr && H->in_manually_txn) {
963+
H->last_app_error = "Cannot change isolation level while a transaction is already open";
964+
return false;
965+
}
966+
H->txn_isolation_level = lval;
967+
if (dbh->auto_commit) {
968+
if (H->tr && !firebird_commit_transaction(dbh, false)) {
969+
return false;
970+
}
971+
if (!_firebird_begin_transaction(dbh)) {
972+
return false;
973+
}
974+
}
975+
} else {
976+
return false;
977+
}
978+
}
979+
}
980+
return true;
965981
}
966982
return false;
967983
}
@@ -1062,6 +1078,64 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
10621078
}
10631079
/* }}} */
10641080

1081+
/* change transaction access mode. writable or readonly */
1082+
static void change_transaction_access_mode(INTERNAL_FUNCTION_PARAMETERS, bool writable) /* {{{ */
1083+
{
1084+
pdo_dbh_t *dbh;
1085+
1086+
ZEND_PARSE_PARAMETERS_NONE();
1087+
1088+
dbh = Z_PDO_DBH_P(ZEND_THIS);
1089+
PDO_CONSTRUCT_CHECK;
1090+
1091+
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
1092+
1093+
if (H->is_writable_txn == writable) {
1094+
RETURN_TRUE;
1095+
}
1096+
1097+
if (H->tr && H->in_manually_txn) {
1098+
H->last_app_error = "Cannot change access mode while a transaction is already open";
1099+
RETURN_FALSE;
1100+
}
1101+
H->is_writable_txn = writable;
1102+
if (dbh->auto_commit) {
1103+
if (H->tr && !firebird_commit_transaction(dbh, false)) {
1104+
RETURN_FALSE;
1105+
}
1106+
if (!_firebird_begin_transaction(dbh)) {
1107+
RETURN_FALSE;
1108+
}
1109+
}
1110+
1111+
RETURN_TRUE;
1112+
}
1113+
/* }}} */
1114+
1115+
/* {{{ change transaction mode to writable */
1116+
PHP_METHOD(PDO_Firebird_Ext, fbWritable)
1117+
{
1118+
change_transaction_access_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
1119+
}
1120+
/* }}} */
1121+
1122+
/* {{{ change transaction mode to readonly */
1123+
PHP_METHOD(PDO_Firebird_Ext, fbReadonly)
1124+
{
1125+
change_transaction_access_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
1126+
}
1127+
/* }}} */
1128+
1129+
static const zend_function_entry *pdo_firebird_get_driver_methods(pdo_dbh_t *dbh, int kind)
1130+
{
1131+
switch (kind) {
1132+
case PDO_DBH_DRIVER_METHOD_KIND_DBH:
1133+
return class_PDO_Firebird_Ext_methods;
1134+
default:
1135+
return NULL;
1136+
}
1137+
}
1138+
10651139
/* {{{ firebird_in_manually_transaction */
10661140
static bool firebird_in_manually_transaction(pdo_dbh_t *dbh)
10671141
{
@@ -1083,7 +1157,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10831157
pdo_firebird_fetch_error_func,
10841158
firebird_handle_get_attribute,
10851159
NULL, /* check_liveness */
1086-
NULL, /* get driver methods */
1160+
pdo_firebird_get_driver_methods,
10871161
NULL, /* request shutdown */
10881162
firebird_in_manually_transaction,
10891163
NULL /* get gc */
@@ -1167,6 +1241,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
11671241
}
11681242

11691243
H->in_manually_txn = 0;
1244+
H->is_writable_txn = 1;
11701245
if (dbh->auto_commit && !H->tr) {
11711246
ret = _firebird_begin_transaction(dbh);
11721247
}
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
@@ -76,6 +76,7 @@ typedef struct {
7676
/* the transaction handle */
7777
isc_tr_handle tr;
7878
bool in_manually_txn:1;
79+
bool is_writable_txn:1;
7980

8081
/* the last error that didn't come from the API */
8182
char const *last_app_error;
@@ -92,6 +93,8 @@ typedef struct {
9293

9394
unsigned _reserved:29;
9495

96+
/* transaction isolation level */
97+
zend_ulong txn_isolation_level;
9598
} pdo_firebird_db_handle;
9699

97100

@@ -138,6 +141,12 @@ enum {
138141
PDO_FB_ATTR_DATE_FORMAT = PDO_ATTR_DRIVER_SPECIFIC,
139142
PDO_FB_ATTR_TIME_FORMAT,
140143
PDO_FB_ATTR_TIMESTAMP_FORMAT,
144+
145+
/* transaction isolation level */
146+
PDO_FB_TRANSACTION_ISOLATION_LEVEL,
147+
PDO_FB_READ_COMMITTED,
148+
PDO_FB_REPEATABLE_READ,
149+
PDO_FB_SERIALIZABLE,
141150
};
142151

143152
#endif /* PHP_PDO_FIREBIRD_INT_H */

0 commit comments

Comments
 (0)