|
5 | 5 |
|
6 | 6 | package com.microsoft.sqlserver.jdbc; |
7 | 7 |
|
| 8 | +import java.net.SocketException; |
8 | 9 | import java.sql.CallableStatement; |
9 | 10 | import java.sql.ResultSet; |
10 | 11 | import java.sql.SQLException; |
|
26 | 27 |
|
27 | 28 | import com.microsoft.sqlserver.jdbc.SQLServerError.TransientError; |
28 | 29 |
|
| 30 | + |
29 | 31 | /** |
30 | 32 | * Implements Transaction id used to recover transactions. |
31 | 33 | */ |
@@ -764,7 +766,7 @@ private XAReturnValue dtc_XA_interface(int nType, Xid xid, int xaFlags) throws X |
764 | 766 | xaLogger.finer(toString() + " exception:" + ex); |
765 | 767 |
|
766 | 768 | if (ex.getMessage().equals(SQLServerException.getErrString("R_noServerResponse")) |
767 | | - || TransientError.isTransientError(ex.getSQLServerError())) { |
| 769 | + || TransientError.isTransientError(ex.getSQLServerError()) || isResourceManagerFailure(ex)) { |
768 | 770 | XAException e = new XAException(ex.toString()); |
769 | 771 | e.errorCode = XAException.XAER_RMFAIL; |
770 | 772 | throw e; |
@@ -943,4 +945,62 @@ private static int nextResourceID() { |
943 | 945 | return baseResourceID.incrementAndGet(); |
944 | 946 | } |
945 | 947 |
|
| 948 | + private enum ResourceManagerFailure { |
| 949 | + CONN_RESET("Connection reset"); |
| 950 | + |
| 951 | + private final String errString; |
| 952 | + |
| 953 | + ResourceManagerFailure(String errString) { |
| 954 | + this.errString = errString; |
| 955 | + } |
| 956 | + |
| 957 | + @Override |
| 958 | + public String toString() { |
| 959 | + return errString; |
| 960 | + } |
| 961 | + |
| 962 | + static ResourceManagerFailure fromString(String errString) { |
| 963 | + for (ResourceManagerFailure resourceManagerFailure : ResourceManagerFailure.values()) { |
| 964 | + if (errString.equalsIgnoreCase(resourceManagerFailure.toString())) { |
| 965 | + return resourceManagerFailure; |
| 966 | + } |
| 967 | + } |
| 968 | + return null; |
| 969 | + } |
| 970 | + } |
| 971 | + |
| 972 | + /** |
| 973 | + * Check if the root exception of the throwable should be a XAER_RMFAIL exception |
| 974 | + * |
| 975 | + * @param throwable |
| 976 | + * The exception to check if the root cause should be a XAER_RMFAIL |
| 977 | + * |
| 978 | + * @return True if XAER_RMFAIL, otherwise false |
| 979 | + */ |
| 980 | + private boolean isResourceManagerFailure(Throwable throwable) { |
| 981 | + Throwable root = Util.getRootCause(throwable); |
| 982 | + |
| 983 | + if (null == root) { |
| 984 | + return false; |
| 985 | + } |
| 986 | + |
| 987 | + ResourceManagerFailure err = ResourceManagerFailure.fromString(root.getMessage()); |
| 988 | + |
| 989 | + if (null == err) { |
| 990 | + return false; |
| 991 | + } |
| 992 | + |
| 993 | + // Add as needed here for future XAER_RMFAIL exceptions |
| 994 | + if (root instanceof SocketException) { |
| 995 | + switch (err) { |
| 996 | + case CONN_RESET: |
| 997 | + return true; |
| 998 | + default: |
| 999 | + return false; |
| 1000 | + } |
| 1001 | + } |
| 1002 | + |
| 1003 | + return false; |
| 1004 | + } |
| 1005 | + |
946 | 1006 | } |
0 commit comments