|
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"
|
33 | 34 |
|
@@ -700,48 +701,31 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
|
700 | 701 | static bool _firebird_begin_transaction(pdo_dbh_t *dbh) /* {{{ */
|
701 | 702 | {
|
702 | 703 | 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 */ |
| 704 | + char tpb[5] = { isc_tpb_version3 }, *ptpb = tpb + strlen(tpb); |
| 705 | + |
| 706 | + switch (H->txn_isolation_level) { |
| 707 | + case PDO_FB_READ_COMMITTED: |
708 | 708 | *ptpb++ = isc_tpb_read_committed;
|
709 | 709 | *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 { |
| 710 | + break; |
| 711 | + |
| 712 | + case PDO_FB_SERIALIZABLE: |
719 | 713 | *ptpb++ = isc_tpb_consistency;
|
720 |
| - dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_SERIALIZABLE); |
721 |
| - } |
722 |
| - } |
| 714 | + break; |
723 | 715 |
|
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 |
| - } |
| 716 | + case PDO_FB_REPEATABLE_READ: |
| 717 | + default: |
| 718 | + *ptpb++ = isc_tpb_concurrency; |
| 719 | + break; |
732 | 720 | }
|
733 | 721 |
|
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 |
| - } |
| 722 | + if (H->is_writable_txn) { |
| 723 | + *ptpb++ = isc_tpb_write; |
| 724 | + } else { |
| 725 | + *ptpb++ = isc_tpb_read; |
742 | 726 | }
|
743 |
| -#endif |
744 |
| - if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb-tpb), tpb)) { |
| 727 | + |
| 728 | + if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb - tpb), tpb)) { |
745 | 729 | RECORD_ERROR(dbh);
|
746 | 730 | return false;
|
747 | 731 | }
|
@@ -882,6 +866,7 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
|
882 | 866 | {
|
883 | 867 | pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
|
884 | 868 | bool bval;
|
| 869 | + zend_long lval; |
885 | 870 |
|
886 | 871 | switch (attr) {
|
887 | 872 | case PDO_ATTR_AUTOCOMMIT:
|
@@ -962,6 +947,60 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *
|
962 | 947 | zend_string_release_ex(str, 0);
|
963 | 948 | }
|
964 | 949 | return true;
|
| 950 | + |
| 951 | + case PDO_FB_TRANSACTION_ISOLATION_LEVEL: |
| 952 | + { |
| 953 | + if (!pdo_get_long_param(&lval, val)) { |
| 954 | + return false; |
| 955 | + } |
| 956 | + if (H->txn_isolation_level != lval) { |
| 957 | + if (lval == PDO_FB_READ_COMMITTED || |
| 958 | + lval == PDO_FB_REPEATABLE_READ || |
| 959 | + lval == PDO_FB_SERIALIZABLE |
| 960 | + ) { |
| 961 | + if (H->tr && H->in_manually_txn) { |
| 962 | + H->last_app_error = "Cannot change isolation level while a transaction is already open"; |
| 963 | + return false; |
| 964 | + } |
| 965 | + H->txn_isolation_level = lval; |
| 966 | + if (dbh->auto_commit) { |
| 967 | + if (H->tr && !firebird_commit_transaction(dbh, false)) { |
| 968 | + return false; |
| 969 | + } |
| 970 | + if (!_firebird_begin_transaction(dbh)) { |
| 971 | + return false; |
| 972 | + } |
| 973 | + } |
| 974 | + } else { |
| 975 | + return false; |
| 976 | + } |
| 977 | + } |
| 978 | + } |
| 979 | + return true; |
| 980 | + |
| 981 | + case PDO_FB_WRITABLE_TRANSACTION: |
| 982 | + { |
| 983 | + if (!pdo_get_bool_param(&bval, val)) { |
| 984 | + return false; |
| 985 | + } |
| 986 | + |
| 987 | + if (H->is_writable_txn != bval) { |
| 988 | + if (H->tr && H->in_manually_txn) { |
| 989 | + H->last_app_error = "Cannot change access mode while a transaction is already open"; |
| 990 | + return false; |
| 991 | + } |
| 992 | + H->is_writable_txn = bval; |
| 993 | + if (dbh->auto_commit) { |
| 994 | + if (H->tr && !firebird_commit_transaction(dbh, false)) { |
| 995 | + return false; |
| 996 | + } |
| 997 | + if (!_firebird_begin_transaction(dbh)) { |
| 998 | + return false; |
| 999 | + } |
| 1000 | + } |
| 1001 | + } |
| 1002 | + } |
| 1003 | + return true; |
965 | 1004 | }
|
966 | 1005 | return false;
|
967 | 1006 | }
|
@@ -1034,6 +1073,14 @@ static int firebird_handle_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v
|
1034 | 1073 | case PDO_ATTR_FETCH_TABLE_NAMES:
|
1035 | 1074 | ZVAL_BOOL(val, H->fetch_table_names);
|
1036 | 1075 | return 1;
|
| 1076 | + |
| 1077 | + case PDO_FB_TRANSACTION_ISOLATION_LEVEL: |
| 1078 | + ZVAL_LONG(val, H->txn_isolation_level); |
| 1079 | + return 1; |
| 1080 | + |
| 1081 | + case PDO_FB_WRITABLE_TRANSACTION: |
| 1082 | + ZVAL_BOOL(val, H->is_writable_txn); |
| 1083 | + return 1; |
1037 | 1084 | }
|
1038 | 1085 | return 0;
|
1039 | 1086 | }
|
@@ -1116,6 +1163,21 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
|
1116 | 1163 | dbh->password = pestrdup(vars[5].optval, dbh->is_persistent);
|
1117 | 1164 | }
|
1118 | 1165 |
|
| 1166 | + H->in_manually_txn = 0; |
| 1167 | + H->is_writable_txn = 1; |
| 1168 | + if (driver_options) { |
| 1169 | + H->is_writable_txn = pdo_attr_lval(driver_options, PDO_FB_WRITABLE_TRANSACTION, 1); |
| 1170 | + zend_long txn_isolation_level = pdo_attr_lval(driver_options, PDO_FB_TRANSACTION_ISOLATION_LEVEL, PDO_FB_REPEATABLE_READ); |
| 1171 | + if (txn_isolation_level == PDO_FB_READ_COMMITTED || |
| 1172 | + txn_isolation_level == PDO_FB_REPEATABLE_READ || |
| 1173 | + txn_isolation_level == PDO_FB_SERIALIZABLE |
| 1174 | + ) { |
| 1175 | + H->txn_isolation_level = txn_isolation_level; |
| 1176 | + } else { |
| 1177 | + H->txn_isolation_level = PDO_FB_REPEATABLE_READ; |
| 1178 | + } |
| 1179 | + } |
| 1180 | + |
1119 | 1181 | do {
|
1120 | 1182 | static char const dpb_flags[] = {
|
1121 | 1183 | isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name };
|
@@ -1166,7 +1228,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /*
|
1166 | 1228 | "HY000", H->isc_status[1], errmsg);
|
1167 | 1229 | }
|
1168 | 1230 |
|
1169 |
| - H->in_manually_txn = 0; |
1170 | 1231 | if (dbh->auto_commit && !H->tr) {
|
1171 | 1232 | ret = _firebird_begin_transaction(dbh);
|
1172 | 1233 | }
|
|
0 commit comments