Skip to content

Commit 26b7647

Browse files
committed
Added transaction isolation level and access mode
1 parent 10b02c5 commit 26b7647

File tree

5 files changed

+160
-36
lines changed

5 files changed

+160
-36
lines changed

ext/pdo_firebird/firebird_driver.c

Lines changed: 114 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
static bool _firebird_commit_transaction(pdo_dbh_t *dbh, bool retain);
@@ -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_write_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
}
@@ -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,67 @@ 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->tr && H->in_manually_txn) {
1089+
H->last_app_error = "Cannot change access mode while a transaction is already open";
1090+
PDO_HANDLE_DBH_ERR();
1091+
return false;
1092+
}
1093+
H->is_write_txn = writable;
1094+
if (dbh->auto_commit) {
1095+
if (H->tr && !_firebird_commit_transaction(dbh, false)) {
1096+
return false;
1097+
}
1098+
if (!_firebird_begin_transaction(dbh)) {
1099+
return false;
1100+
}
1101+
}
1102+
return true;
1103+
}
1104+
/* }}} */
1105+
1106+
/* {{{ change transaction mode to writable */
1107+
PHP_METHOD(PDO_Firebird_Ext, fbWritable)
1108+
{
1109+
pdo_dbh_t *dbh;
1110+
1111+
ZEND_PARSE_PARAMETERS_NONE();
1112+
1113+
dbh = Z_PDO_DBH_P(ZEND_THIS);
1114+
PDO_CONSTRUCT_CHECK;
1115+
1116+
RETURN_BOOL(change_transaction_access_mode(dbh, true));
1117+
}
1118+
/* }}} */
1119+
1120+
/* {{{ change transaction mode to readonly */
1121+
PHP_METHOD(PDO_Firebird_Ext, fbReadonly)
1122+
{
1123+
pdo_dbh_t *dbh;
1124+
1125+
ZEND_PARSE_PARAMETERS_NONE();
1126+
1127+
dbh = Z_PDO_DBH_P(ZEND_THIS);
1128+
PDO_CONSTRUCT_CHECK;
1129+
1130+
RETURN_BOOL(change_transaction_access_mode(dbh, false));
1131+
}
1132+
/* }}} */
1133+
1134+
static const zend_function_entry *pdo_firebird_get_driver_methods(pdo_dbh_t *dbh, int kind)
1135+
{
1136+
switch (kind) {
1137+
case PDO_DBH_DRIVER_METHOD_KIND_DBH:
1138+
return class_PDO_Firebird_Ext_methods;
1139+
default:
1140+
return NULL;
1141+
}
1142+
}
1143+
10671144
/* {{{ firebird_in_manually_transaction */
10681145
static bool firebird_in_manually_transaction(pdo_dbh_t *dbh)
10691146
{
@@ -1085,7 +1162,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
10851162
pdo_firebird_fetch_error_func,
10861163
firebird_handle_get_attribute,
10871164
NULL, /* check_liveness */
1088-
NULL, /* get driver methods */
1165+
pdo_firebird_get_driver_methods,
10891166
NULL, /* request shutdown */
10901167
firebird_in_manually_transaction,
10911168
NULL /* get gc */
@@ -1169,6 +1246,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
11691246
}
11701247

11711248
H->in_manually_txn = 0;
1249+
H->is_write_txn = 1;
11721250
if (dbh->auto_commit && !H->tr) {
11731251
ret = _firebird_begin_transaction(dbh);
11741252
}
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_write_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)