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 , bool retain );
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 , /* release */ false);
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,28 +808,105 @@ static bool firebird_handle_begin(pdo_dbh_t *dbh) /* {{{ */
809
808
}
810
809
/* }}} */
811
810
812
- /* called by PDO to commit a transaction */
813
- static bool firebird_handle_commit (pdo_dbh_t * dbh ) /* {{{ */
811
+ /* called by PDO to start a transaction */
812
+ static bool firebird_handle_manually_begin (pdo_dbh_t * dbh ) /* {{{ */
814
813
{
815
814
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
816
815
817
- if (isc_commit_transaction (H -> isc_status , & H -> tr )) {
818
- php_firebird_error (dbh );
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 )) {
819
826
return false;
820
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
+
861
+ /* called by PDO to commit a transaction */
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 , dbh -> auto_commit )) {
866
+ return false;
867
+ }
868
+ H -> in_manually_txn = 0 ;
869
+ return true;
870
+ }
871
+ /* }}} */
872
+
873
+ /* php_firebird_rollback_transaction */
874
+ static bool php_firebird_rollback_transaction (pdo_dbh_t * dbh , bool retain ) /* {{{ */
875
+ {
876
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
877
+
878
+ /**
879
+ * `retaining` keeps the transaction open without closing it.
880
+ *
881
+ * firebird needs to always have a transaction open to emulate autocommit mode,
882
+ * and in autocommit mode it keeps the transaction open.
883
+ *
884
+ * Same as close and then begin again, but use retain to save overhead.
885
+ */
886
+ if (retain ) {
887
+ if (isc_rollback_retaining (H -> isc_status , & H -> tr )) {
888
+ php_firebird_error (dbh );
889
+ return false;
890
+ }
891
+ } else {
892
+ if (isc_rollback_transaction (H -> isc_status , & H -> tr )) {
893
+ php_firebird_error (dbh );
894
+ return false;
895
+ }
896
+ }
821
897
return true;
822
898
}
823
899
/* }}} */
824
900
825
901
/* called by PDO to rollback a transaction */
826
- static bool firebird_handle_rollback (pdo_dbh_t * dbh ) /* {{{ */
902
+ static bool firebird_handle_manually_rollback (pdo_dbh_t * dbh ) /* {{{ */
827
903
{
828
904
pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
829
905
830
- if (isc_rollback_transaction (H -> isc_status , & H -> tr )) {
831
- php_firebird_error (dbh );
906
+ if (!php_firebird_rollback_transaction (dbh , dbh -> auto_commit )) {
832
907
return false;
833
908
}
909
+ H -> in_manually_txn = 0 ;
834
910
return true;
835
911
}
836
912
/* }}} */
@@ -848,16 +924,6 @@ static int php_firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sq
848
924
return 0 ;
849
925
}
850
926
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
927
/* allocate the statement */
862
928
if (isc_dsql_allocate_statement (H -> isc_status , & H -> db , s )) {
863
929
php_firebird_error (dbh );
@@ -898,21 +964,31 @@ static bool pdo_firebird_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val
898
964
return false;
899
965
}
900
966
967
+ if (H -> in_manually_txn ) {
968
+ /* change auto commit mode with an open transaction is illegal, because
969
+ we won't know what to do with it */
970
+ const char * msg = "Cannot change autocommit mode while a transaction is already open" ;
971
+ php_firebird_error_with_info (dbh , "HY000" , strlen ("HY000" ), msg , strlen (msg ));
972
+ return false;
973
+ }
974
+
901
975
/* ignore if the new value equals the old one */
902
976
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 ;
977
+ if (bval ) {
978
+ /* change to auto commit mode */
979
+ /* If the transaction is not started, start it. */
980
+ if (!H -> tr ) {
981
+ if (!php_firebird_begin_transaction (dbh )) {
982
+ return false;
983
+ }
984
+ }
985
+ } else {
986
+ /* change to not auto commit mode */
987
+ /* close the transaction if exists */
988
+ if (H -> tr ) {
989
+ if (!php_firebird_commit_transaction (dbh , /* release */ false)) {
990
+ return false;
914
991
}
915
- dbh -> in_txn = false;
916
992
}
917
993
}
918
994
dbh -> auto_commit = bval ;
@@ -1058,22 +1134,35 @@ static void pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval
1058
1134
}
1059
1135
/* }}} */
1060
1136
1137
+ /* {{{ firebird_in_manually_transaction */
1138
+ static bool pdo_firebird_in_manually_transaction (pdo_dbh_t * dbh )
1139
+ {
1140
+ /**
1141
+ * we can tell if a transaction exists now by checking H->tr,
1142
+ * but which will always be true in autocommit mode.
1143
+ * So this function checks if there is currently a "manually begun transaction".
1144
+ */
1145
+ pdo_firebird_db_handle * H = (pdo_firebird_db_handle * )dbh -> driver_data ;
1146
+ return H -> in_manually_txn ;
1147
+ }
1148
+ /* }}} */
1149
+
1061
1150
static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
1062
1151
firebird_handle_closer ,
1063
1152
firebird_handle_preparer ,
1064
1153
firebird_handle_doer ,
1065
1154
firebird_handle_quoter ,
1066
- firebird_handle_begin ,
1067
- firebird_handle_commit ,
1068
- firebird_handle_rollback ,
1155
+ firebird_handle_manually_begin ,
1156
+ firebird_handle_manually_commit ,
1157
+ firebird_handle_manually_rollback ,
1069
1158
pdo_firebird_set_attribute ,
1070
1159
NULL , /* last_id not supported */
1071
1160
pdo_firebird_fetch_error_func ,
1072
1161
pdo_firebird_get_attribute ,
1073
1162
NULL , /* check_liveness */
1074
1163
NULL , /* get driver methods */
1075
1164
NULL , /* request shutdown */
1076
- NULL , /* in transaction, use PDO's internal tracking mechanism */
1165
+ pdo_firebird_in_manually_transaction ,
1077
1166
NULL /* get gc */
1078
1167
};
1079
1168
/* }}} */
@@ -1154,6 +1243,11 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
1154
1243
"HY000" , H -> isc_status [1 ], errmsg );
1155
1244
}
1156
1245
1246
+ H -> in_manually_txn = 0 ;
1247
+ if (dbh -> auto_commit && !H -> tr ) {
1248
+ ret = php_firebird_begin_transaction (dbh );
1249
+ }
1250
+
1157
1251
if (!ret ) {
1158
1252
firebird_handle_closer (dbh );
1159
1253
}
0 commit comments