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 * );
35
37
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
702
704
static bool _firebird_begin_transaction (pdo_dbh_t * dbh ) /* {{{ */
703
705
{
704
706
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 :
710
711
* ptpb ++ = isc_tpb_read_committed ;
711
712
* 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 :
721
716
* ptpb ++ = isc_tpb_consistency ;
722
- dbh -> transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL ^PDO_TRANS_SERIALIZABLE );
723
- }
724
- }
717
+ break ;
725
718
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 ;
734
723
}
735
724
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 ;
744
729
}
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 )) {
747
732
RECORD_ERROR (dbh );
748
733
return false;
749
734
}
@@ -884,6 +869,7 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
884
869
{
885
870
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
886
871
bool bval ;
872
+ zend_long lval ;
887
873
888
874
switch (attr ) {
889
875
case PDO_ATTR_AUTOCOMMIT :
@@ -964,6 +950,36 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
964
950
zend_string_release_ex (str , 0 );
965
951
}
966
952
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;
967
983
}
968
984
return false;
969
985
}
@@ -1064,6 +1080,67 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
1064
1080
}
1065
1081
/* }}} */
1066
1082
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
+
1067
1144
/* {{{ firebird_in_manually_transaction */
1068
1145
static bool firebird_in_manually_transaction (pdo_dbh_t * dbh )
1069
1146
{
@@ -1085,7 +1162,7 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
1085
1162
pdo_firebird_fetch_error_func ,
1086
1163
firebird_handle_get_attribute ,
1087
1164
NULL , /* check_liveness */
1088
- NULL , /* get driver methods */
1165
+ pdo_firebird_get_driver_methods ,
1089
1166
NULL , /* request shutdown */
1090
1167
firebird_in_manually_transaction ,
1091
1168
NULL /* get gc */
@@ -1169,6 +1246,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1169
1246
}
1170
1247
1171
1248
H -> in_manually_txn = 0 ;
1249
+ H -> is_write_txn = 1 ;
1172
1250
if (dbh -> auto_commit && !H -> tr ) {
1173
1251
ret = _firebird_begin_transaction (dbh );
1174
1252
}
0 commit comments