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
}
@@ -1034,6 +1059,14 @@ static int firebird_handle_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v
1034
1059
case PDO_ATTR_FETCH_TABLE_NAMES :
1035
1060
ZVAL_BOOL (val , H -> fetch_table_names );
1036
1061
return 1 ;
1062
+
1063
+ case PDO_FB_TRANSACTION_ISOLATION_LEVEL :
1064
+ ZVAL_LONG (val , H -> txn_isolation_level );
1065
+ return 1 ;
1066
+
1067
+ case PDO_FB_WRITABLE_TRANSACTION :
1068
+ ZVAL_BOOL (val , H -> is_writable_txn );
1069
+ return 1 ;
1037
1070
}
1038
1071
return 0 ;
1039
1072
}
@@ -1062,6 +1095,70 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
1062
1095
}
1063
1096
/* }}} */
1064
1097
1098
+ /* change transaction access mode. writable or readonly */
1099
+ static bool firebird_change_transaction_access_mode (pdo_dbh_t * dbh , bool writable ) /* {{{ */
1100
+ {
1101
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
1102
+
1103
+ if (H -> is_writable_txn == writable ) {
1104
+ return true;
1105
+ }
1106
+
1107
+ if (H -> tr && H -> in_manually_txn ) {
1108
+ H -> last_app_error = "Cannot change access mode while a transaction is already open" ;
1109
+ return false;
1110
+ }
1111
+ H -> is_writable_txn = writable ;
1112
+ if (dbh -> auto_commit ) {
1113
+ if (H -> tr && !firebird_commit_transaction (dbh , false)) {
1114
+ return false;
1115
+ }
1116
+ if (!_firebird_begin_transaction (dbh )) {
1117
+ return false;
1118
+ }
1119
+ }
1120
+
1121
+ return true;
1122
+ }
1123
+
1124
+ /* fbWritable or fbReadonly */
1125
+ static void firebird_fb_access_mode (INTERNAL_FUNCTION_PARAMETERS , bool writable ) /* {{{ */
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 (firebird_change_transaction_access_mode (dbh , writable ));
1135
+ }
1136
+ /* }}} */
1137
+
1138
+ /* {{{ change transaction mode to writable */
1139
+ PHP_METHOD (PDO_Firebird_Ext , fbWritable )
1140
+ {
1141
+ firebird_fb_access_mode (INTERNAL_FUNCTION_PARAM_PASSTHRU , true);
1142
+ }
1143
+ /* }}} */
1144
+
1145
+ /* {{{ change transaction mode to readonly */
1146
+ PHP_METHOD (PDO_Firebird_Ext , fbReadonly )
1147
+ {
1148
+ firebird_fb_access_mode (INTERNAL_FUNCTION_PARAM_PASSTHRU , false);
1149
+ }
1150
+ /* }}} */
1151
+
1152
+ static const zend_function_entry * pdo_firebird_get_driver_methods (pdo_dbh_t * dbh , int kind )
1153
+ {
1154
+ switch (kind ) {
1155
+ case PDO_DBH_DRIVER_METHOD_KIND_DBH :
1156
+ return class_PDO_Firebird_Ext_methods ;
1157
+ default :
1158
+ return NULL ;
1159
+ }
1160
+ }
1161
+
1065
1162
/* {{{ firebird_in_manually_transaction */
1066
1163
static bool firebird_in_manually_transaction (pdo_dbh_t * dbh )
1067
1164
{
@@ -1083,7 +1180,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
1083
1180
pdo_firebird_fetch_error_func ,
1084
1181
firebird_handle_get_attribute ,
1085
1182
NULL , /* check_liveness */
1086
- NULL , /* get driver methods */
1183
+ pdo_firebird_get_driver_methods ,
1087
1184
NULL , /* request shutdown */
1088
1185
firebird_in_manually_transaction ,
1089
1186
NULL /* get gc */
@@ -1116,6 +1213,21 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1116
1213
dbh -> password = pestrdup (vars [5 ].optval , dbh -> is_persistent );
1117
1214
}
1118
1215
1216
+ H -> in_manually_txn = 0 ;
1217
+ H -> is_writable_txn = 1 ;
1218
+ if (driver_options ) {
1219
+ H -> is_writable_txn = pdo_attr_lval (driver_options , PDO_FB_WRITABLE_TRANSACTION , 1 );
1220
+ zend_long txn_isolation_level = pdo_attr_lval (driver_options , PDO_FB_TRANSACTION_ISOLATION_LEVEL , PDO_FB_REPEATABLE_READ );
1221
+ if (txn_isolation_level == PDO_FB_READ_COMMITTED ||
1222
+ txn_isolation_level == PDO_FB_REPEATABLE_READ ||
1223
+ txn_isolation_level == PDO_FB_SERIALIZABLE
1224
+ ) {
1225
+ H -> txn_isolation_level = txn_isolation_level ;
1226
+ } else {
1227
+ H -> txn_isolation_level = PDO_FB_REPEATABLE_READ ;
1228
+ }
1229
+ }
1230
+
1119
1231
do {
1120
1232
static char const dpb_flags [] = {
1121
1233
isc_dpb_user_name , isc_dpb_password , isc_dpb_lc_ctype , isc_dpb_sql_role_name };
@@ -1166,7 +1278,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1166
1278
"HY000" , H -> isc_status [1 ], errmsg );
1167
1279
}
1168
1280
1169
- H -> in_manually_txn = 0 ;
1170
1281
if (dbh -> auto_commit && !H -> tr ) {
1171
1282
ret = _firebird_begin_transaction (dbh );
1172
1283
}
0 commit comments