33
33
34
34
static int php_firebird_alloc_prepare_stmt (pdo_dbh_t * , const zend_string * , XSQLDA * , isc_stmt_handle * ,
35
35
HashTable * );
36
+ static bool php_firebird_rollback_transaction (pdo_dbh_t * dbh );
36
37
37
38
const char CHR_LETTER = 1 ;
38
39
const char CHR_DIGIT = 2 ;
@@ -526,17 +527,14 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */
526
527
{
527
528
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
528
529
529
- if (dbh -> in_txn ) {
530
+ if (H -> tr ) {
530
531
if (dbh -> auto_commit ) {
531
- if (isc_commit_transaction (H -> isc_status , & H -> tr )) {
532
- php_firebird_error (dbh );
533
- }
532
+ php_firebird_commit_transaction (dbh , /* release */ false);
534
533
} else {
535
- if (isc_rollback_transaction (H -> isc_status , & H -> tr )) {
536
- php_firebird_error (dbh );
537
- }
534
+ php_firebird_rollback_transaction (dbh );
538
535
}
539
536
}
537
+ H -> in_manually_txn = 0 ;
540
538
541
539
if (isc_detach_database (H -> isc_status , & H -> db )) {
542
540
php_firebird_error (dbh );
@@ -702,9 +700,10 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /*
702
700
}
703
701
}
704
702
705
- /* commit if we're in auto_commit mode */
706
- if (dbh -> auto_commit && isc_commit_retaining (H -> isc_status , & H -> tr )) {
707
- php_firebird_error (dbh );
703
+ if (dbh -> auto_commit && !H -> in_manually_txn ) {
704
+ if (!php_firebird_commit_transaction (dbh , /* retain */ true)) {
705
+ ret = -1 ;
706
+ }
708
707
}
709
708
710
709
free_statement :
@@ -756,8 +755,8 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
756
755
}
757
756
/* }}} */
758
757
759
- /* called by PDO to start a transaction */
760
- static bool firebird_handle_begin (pdo_dbh_t * dbh ) /* {{{ */
758
+ /* php_firebird_begin_transaction */
759
+ static bool php_firebird_begin_transaction (pdo_dbh_t * dbh ) /* {{{ */
761
760
{
762
761
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
763
762
char tpb [8 ] = { isc_tpb_version3 }, * ptpb = tpb + 1 ;
@@ -809,12 +808,84 @@ static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
809
808
}
810
809
/* }}} */
811
810
811
+ /* called by PDO to start a transaction */
812
+ static bool firebird_handle_manually_begin (pdo_dbh_t * dbh ) /* {{{ */
813
+ {
814
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
815
+
816
+ /**
817
+ * If in autocommit mode and in transaction, we will need to close the transaction once.
818
+ */
819
+ if (dbh -> auto_commit && H -> tr ) {
820
+ if (!php_firebird_commit_transaction (dbh , /* release */ false)) {
821
+ return false;
822
+ }
823
+ }
824
+
825
+ if (!php_firebird_begin_transaction (dbh )) {
826
+ return false;
827
+ }
828
+ H -> in_manually_txn = 1 ;
829
+ return true;
830
+ }
831
+ /* }}} */
832
+
833
+ /* php_firebird_commit_transaction */
834
+ bool php_firebird_commit_transaction (pdo_dbh_t * dbh , bool retain ) /* {{{ */
835
+ {
836
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
837
+
838
+ /**
839
+ * `retaining` keeps the transaction open without closing it.
840
+ *
841
+ * firebird needs to always have a transaction open to emulate autocommit mode,
842
+ * and in autocommit mode it keeps the transaction open.
843
+ *
844
+ * Same as close and then begin again, but use retain to save overhead.
845
+ */
846
+ if (retain ) {
847
+ if (isc_commit_retaining (H -> isc_status , & H -> tr )) {
848
+ php_firebird_error (dbh );
849
+ return false;
850
+ }
851
+ } else {
852
+ if (isc_commit_transaction (H -> isc_status , & H -> tr )) {
853
+ php_firebird_error (dbh );
854
+ return false;
855
+ }
856
+ }
857
+ return true;
858
+ }
859
+ /* }}} */
860
+
812
861
/* called by PDO to commit a transaction */
813
- static bool firebird_handle_commit (pdo_dbh_t * dbh ) /* {{{ */
862
+ static bool firebird_handle_manually_commit (pdo_dbh_t * dbh ) /* {{{ */
863
+ {
864
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
865
+ if (!php_firebird_commit_transaction (dbh , /*release*/ false)) {
866
+ return false;
867
+ }
868
+
869
+ /**
870
+ * If in autocommit mode, begin the transaction again
871
+ * Reopen instead of retain because isolation level may change
872
+ */
873
+ if (dbh -> auto_commit ) {
874
+ if (!php_firebird_begin_transaction (dbh )) {
875
+ return false;
876
+ }
877
+ }
878
+ H -> in_manually_txn = 0 ;
879
+ return true;
880
+ }
881
+ /* }}} */
882
+
883
+ /* php_firebird_rollback_transaction */
884
+ static bool php_firebird_rollback_transaction (pdo_dbh_t * dbh ) /* {{{ */
814
885
{
815
886
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
816
887
817
- if (isc_commit_transaction (H -> isc_status , & H -> tr )) {
888
+ if (isc_rollback_transaction (H -> isc_status , & H -> tr )) {
818
889
php_firebird_error (dbh );
819
890
return false;
820
891
}
@@ -823,14 +894,24 @@ static bool firebird_handle_commit(pdo_dbh_t *dbh) /* {{{ */
823
894
/* }}} */
824
895
825
896
/* called by PDO to rollback a transaction */
826
- static bool firebird_handle_rollback (pdo_dbh_t * dbh ) /* {{{ */
897
+ static bool firebird_handle_manually_rollback (pdo_dbh_t * dbh ) /* {{{ */
827
898
{
828
899
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
829
900
830
- if (isc_rollback_transaction (H -> isc_status , & H -> tr )) {
831
- php_firebird_error (dbh );
901
+ if (!php_firebird_rollback_transaction (dbh )) {
832
902
return false;
833
903
}
904
+
905
+ /**
906
+ * If in autocommit mode, begin the transaction again
907
+ * Reopen instead of retain because isolation level may change
908
+ */
909
+ if (dbh -> auto_commit ) {
910
+ if (!php_firebird_begin_transaction (dbh )) {
911
+ return false;
912
+ }
913
+ }
914
+ H -> in_manually_txn = 0 ;
834
915
return true;
835
916
}
836
917
/* }}} */
@@ -848,16 +929,6 @@ static int php_firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sq
848
929
return 0 ;
849
930
}
850
931
851
- /* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
852
- if (dbh -> auto_commit && !dbh -> in_txn ) {
853
- /* dbh->transaction_flags = PDO_TRANS_READ_UNCOMMITTED; */
854
-
855
- if (!firebird_handle_begin (dbh )) {
856
- return 0 ;
857
- }
858
- dbh -> in_txn = true;
859
- }
860
-
861
932
/* allocate the statement */
862
933
if (isc_dsql_allocate_statement (H -> isc_status , & H -> db , s )) {
863
934
php_firebird_error (dbh );
@@ -898,21 +969,34 @@ static bool pdo_firebird_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val
898
969
return false;
899
970
}
900
971
972
+ if (H -> in_manually_txn ) {
973
+ /* change auto commit mode with an open transaction is illegal, because
974
+ we won't know what to do with it */
975
+ pdo_raise_impl_error (dbh , NULL , "HY000" , "Cannot change autocommit mode while a transaction is already open" );
976
+ return false;
977
+ }
978
+
901
979
/* ignore if the new value equals the old one */
902
980
if (dbh -> auto_commit ^ bval ) {
903
- if (dbh -> in_txn ) {
904
- if (bval ) {
905
- /* turning on auto_commit with an open transaction is illegal, because
906
- we won't know what to do with it */
907
- const char * msg = "Cannot enable auto-commit while a transaction is already open" ;
908
- php_firebird_error_with_info (dbh , "HY000" , strlen ("HY000" ), msg , strlen (msg ));
909
- return false;
910
- } else {
911
- /* close the transaction */
912
- if (!firebird_handle_commit (dbh )) {
913
- break ;
981
+ if (bval ) {
982
+ /* change to auto commit mode.
983
+ * If the transaction is not started, start it.
984
+ * However, this is a fallback since such a situation usually does not occur.
985
+ */
986
+ if (!H -> tr ) {
987
+ if (!php_firebird_begin_transaction (dbh )) {
988
+ return false;
989
+ }
990
+ }
991
+ } else {
992
+ /* change to not auto commit mode.
993
+ * close the transaction if exists.
994
+ * However, this is a fallback since such a situation usually does not occur.
995
+ */
996
+ if (H -> tr ) {
997
+ if (!php_firebird_commit_transaction (dbh , /* release */ false)) {
998
+ return false;
914
999
}
915
- dbh -> in_txn = false;
916
1000
}
917
1001
}
918
1002
dbh -> auto_commit = bval ;
@@ -1058,22 +1142,35 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
1058
1142
}
1059
1143
/* }}} */
1060
1144
1145
+ /* {{{ firebird_in_manually_transaction */
1146
+ static bool pdo_firebird_in_manually_transaction (pdo_dbh_t * dbh )
1147
+ {
1148
+ /**
1149
+ * we can tell if a transaction exists now by checking H->tr,
1150
+ * but which will always be true in autocommit mode.
1151
+ * So this function checks if there is currently a "manually begun transaction".
1152
+ */
1153
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
1154
+ return H -> in_manually_txn ;
1155
+ }
1156
+ /* }}} */
1157
+
1061
1158
static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
1062
1159
firebird_handle_closer ,
1063
1160
firebird_handle_preparer ,
1064
1161
firebird_handle_doer ,
1065
1162
firebird_handle_quoter ,
1066
- firebird_handle_begin ,
1067
- firebird_handle_commit ,
1068
- firebird_handle_rollback ,
1163
+ firebird_handle_manually_begin ,
1164
+ firebird_handle_manually_commit ,
1165
+ firebird_handle_manually_rollback ,
1069
1166
pdo_firebird_set_attribute ,
1070
1167
NULL , /* last_id not supported */
1071
1168
pdo_firebird_fetch_error_func ,
1072
1169
pdo_firebird_get_attribute ,
1073
1170
NULL , /* check_liveness */
1074
1171
NULL , /* get driver methods */
1075
1172
NULL , /* request shutdown */
1076
- NULL , /* in transaction, use PDO's internal tracking mechanism */
1173
+ pdo_firebird_in_manually_transaction ,
1077
1174
NULL /* get gc */
1078
1175
};
1079
1176
/* }}} */
@@ -1154,6 +1251,11 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1154
1251
"HY000" , H -> isc_status [1 ], errmsg );
1155
1252
}
1156
1253
1254
+ H -> in_manually_txn = 0 ;
1255
+ if (dbh -> auto_commit && !H -> tr ) {
1256
+ ret = php_firebird_begin_transaction (dbh );
1257
+ }
1258
+
1157
1259
if (!ret ) {
1158
1260
firebird_handle_closer (dbh );
1159
1261
}
0 commit comments