28
28
#include "ext/standard/info.h"
29
29
#include "pdo/php_pdo.h"
30
30
#include "pdo/php_pdo_driver.h"
31
+ #include "pdo/php_pdo_error.h"
31
32
#include "php_pdo_firebird.h"
32
33
#include "php_pdo_firebird_int.h"
34
+ #include "firebird_driver_arginfo.h"
33
35
34
36
static int firebird_alloc_prepare_stmt (pdo_dbh_t * , const zend_string * , XSQLDA * , isc_stmt_handle * , HashTable * );
37
+ static bool firebird_change_transaction_access_mode (pdo_dbh_t * dbh , bool writable );
35
38
36
39
const char CHR_LETTER = 1 ;
37
40
const char CHR_DIGIT = 2 ;
@@ -700,48 +703,31 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
700
703
static bool _firebird_begin_transaction (pdo_dbh_t * dbh ) /* {{{ */
701
704
{
702
705
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 */
706
+ char tpb [5 ] = { isc_tpb_version3 }, * ptpb = tpb + strlen (tpb );
707
+
708
+ switch (H -> txn_isolation_level ) {
709
+ case PDO_FB_READ_COMMITTED :
708
710
* ptpb ++ = isc_tpb_read_committed ;
709
711
* 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 {
712
+ break ;
713
+
714
+ case PDO_FB_SERIALIZABLE :
719
715
* ptpb ++ = isc_tpb_consistency ;
720
- dbh -> transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL ^PDO_TRANS_SERIALIZABLE );
721
- }
722
- }
716
+ break ;
723
717
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
- }
718
+ case PDO_FB_REPEATABLE_READ :
719
+ default :
720
+ * ptpb ++ = isc_tpb_concurrency ;
721
+ break ;
732
722
}
733
723
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
- }
724
+ if (H -> is_writable_txn ) {
725
+ * ptpb ++ = isc_tpb_write ;
726
+ } else {
727
+ * ptpb ++ = isc_tpb_read ;
742
728
}
743
- #endif
744
- if (isc_start_transaction (H -> isc_status , & H -> tr , 1 , & H -> db , (unsigned short )(ptpb - tpb ), tpb )) {
729
+
730
+ if (isc_start_transaction (H -> isc_status , & H -> tr , 1 , & H -> db , (unsigned short )(ptpb - tpb ), tpb )) {
745
731
RECORD_ERROR (dbh );
746
732
return false;
747
733
}
@@ -882,6 +868,7 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
882
868
{
883
869
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
884
870
bool bval ;
871
+ zend_long lval ;
885
872
886
873
switch (attr ) {
887
874
case PDO_ATTR_AUTOCOMMIT :
@@ -962,6 +949,44 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
962
949
zend_string_release_ex (str , 0 );
963
950
}
964
951
return true;
952
+
953
+ case PDO_FB_TRANSACTION_ISOLATION_LEVEL :
954
+ {
955
+ if (!pdo_get_long_param (& lval , val )) {
956
+ return false;
957
+ }
958
+ if (H -> txn_isolation_level != lval ) {
959
+ if (lval == PDO_FB_READ_COMMITTED ||
960
+ lval == PDO_FB_REPEATABLE_READ ||
961
+ lval == PDO_FB_SERIALIZABLE
962
+ ) {
963
+ if (H -> tr && H -> in_manually_txn ) {
964
+ H -> last_app_error = "Cannot change isolation level while a transaction is already open" ;
965
+ return false;
966
+ }
967
+ H -> txn_isolation_level = lval ;
968
+ if (dbh -> auto_commit ) {
969
+ if (H -> tr && !firebird_commit_transaction (dbh , false)) {
970
+ return false;
971
+ }
972
+ if (!_firebird_begin_transaction (dbh )) {
973
+ return false;
974
+ }
975
+ }
976
+ } else {
977
+ return false;
978
+ }
979
+ }
980
+ }
981
+ return true;
982
+
983
+ case PDO_FB_WRITABLE_TRANSACTION :
984
+ {
985
+ if (!pdo_get_bool_param (& bval , val )) {
986
+ return false;
987
+ }
988
+ return firebird_change_transaction_access_mode (dbh , bval );
989
+ }
965
990
}
966
991
return false;
967
992
}
@@ -1062,6 +1087,70 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
1062
1087
}
1063
1088
/* }}} */
1064
1089
1090
+ /* change transaction access mode. writable or readonly */
1091
+ static bool firebird_change_transaction_access_mode (pdo_dbh_t * dbh , bool writable ) /* {{{ */
1092
+ {
1093
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
1094
+
1095
+ if (H -> is_writable_txn == writable ) {
1096
+ return true;
1097
+ }
1098
+
1099
+ if (H -> tr && H -> in_manually_txn ) {
1100
+ H -> last_app_error = "Cannot change access mode while a transaction is already open" ;
1101
+ return false;
1102
+ }
1103
+ H -> is_writable_txn = writable ;
1104
+ if (dbh -> auto_commit ) {
1105
+ if (H -> tr && !firebird_commit_transaction (dbh , false)) {
1106
+ return false;
1107
+ }
1108
+ if (!_firebird_begin_transaction (dbh )) {
1109
+ return false;
1110
+ }
1111
+ }
1112
+
1113
+ return true;
1114
+ }
1115
+
1116
+ /* fbWritable or fbReadonly */
1117
+ static void firebird_fb_access_mode (INTERNAL_FUNCTION_PARAMETERS , bool writable ) /* {{{ */
1118
+ {
1119
+ pdo_dbh_t * dbh ;
1120
+
1121
+ ZEND_PARSE_PARAMETERS_NONE ();
1122
+
1123
+ dbh = Z_PDO_DBH_P (ZEND_THIS );
1124
+ PDO_CONSTRUCT_CHECK ;
1125
+
1126
+ RETURN_BOOL (firebird_change_transaction_access_mode (dbh , writable ));
1127
+ }
1128
+ /* }}} */
1129
+
1130
+ /* {{{ change transaction mode to writable */
1131
+ PHP_METHOD (PDO_Firebird_Ext , fbWritable )
1132
+ {
1133
+ firebird_fb_access_mode (INTERNAL_FUNCTION_PARAM_PASSTHRU , true);
1134
+ }
1135
+ /* }}} */
1136
+
1137
+ /* {{{ change transaction mode to readonly */
1138
+ PHP_METHOD (PDO_Firebird_Ext , fbReadonly )
1139
+ {
1140
+ firebird_fb_access_mode (INTERNAL_FUNCTION_PARAM_PASSTHRU , false);
1141
+ }
1142
+ /* }}} */
1143
+
1144
+ static const zend_function_entry * pdo_firebird_get_driver_methods (pdo_dbh_t * dbh , int kind )
1145
+ {
1146
+ switch (kind ) {
1147
+ case PDO_DBH_DRIVER_METHOD_KIND_DBH :
1148
+ return class_PDO_Firebird_Ext_methods ;
1149
+ default :
1150
+ return NULL ;
1151
+ }
1152
+ }
1153
+
1065
1154
/* {{{ firebird_in_manually_transaction */
1066
1155
static bool firebird_in_manually_transaction (pdo_dbh_t * dbh )
1067
1156
{
@@ -1083,7 +1172,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
1083
1172
pdo_firebird_fetch_error_func ,
1084
1173
firebird_handle_get_attribute ,
1085
1174
NULL , /* check_liveness */
1086
- NULL , /* get driver methods */
1175
+ pdo_firebird_get_driver_methods ,
1087
1176
NULL , /* request shutdown */
1088
1177
firebird_in_manually_transaction ,
1089
1178
NULL /* get gc */
@@ -1116,6 +1205,20 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1116
1205
dbh -> password = pestrdup (vars [5 ].optval , dbh -> is_persistent );
1117
1206
}
1118
1207
1208
+ H -> in_manually_txn = 0 ;
1209
+ if (driver_options ) {
1210
+ H -> is_writable_txn = pdo_attr_lval (driver_options , PDO_FB_WRITABLE_TRANSACTION , 1 );
1211
+ zend_long txn_isolation_level = pdo_attr_lval (driver_options , PDO_FB_TRANSACTION_ISOLATION_LEVEL , PDO_FB_REPEATABLE_READ );
1212
+ if (txn_isolation_level == PDO_FB_READ_COMMITTED ||
1213
+ txn_isolation_level == PDO_FB_REPEATABLE_READ ||
1214
+ txn_isolation_level == PDO_FB_SERIALIZABLE
1215
+ ) {
1216
+ H -> txn_isolation_level = txn_isolation_level ;
1217
+ } else {
1218
+ H -> txn_isolation_level = PDO_FB_REPEATABLE_READ ;
1219
+ }
1220
+ }
1221
+
1119
1222
do {
1120
1223
static char const dpb_flags [] = {
1121
1224
isc_dpb_user_name , isc_dpb_password , isc_dpb_lc_ctype , isc_dpb_sql_role_name };
@@ -1166,7 +1269,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1166
1269
"HY000" , H -> isc_status [1 ], errmsg );
1167
1270
}
1168
1271
1169
- H -> in_manually_txn = 0 ;
1170
1272
if (dbh -> auto_commit && !H -> tr ) {
1171
1273
ret = _firebird_begin_transaction (dbh );
1172
1274
}
0 commit comments