|
38 | 38 | import static javax.transaction.xa.XAException.XAER_DUPID; |
39 | 39 | import static javax.transaction.xa.XAException.XAER_INVAL; |
40 | 40 | import static javax.transaction.xa.XAException.XAER_NOTA; |
| 41 | +import static javax.transaction.xa.XAException.XAER_OUTSIDE; |
41 | 42 | import static javax.transaction.xa.XAException.XAER_PROTO; |
42 | 43 | import static javax.transaction.xa.XAException.XAER_RMERR; |
43 | 44 | import static javax.transaction.xa.XAException.XAER_RMFAIL; |
@@ -171,7 +172,20 @@ private Association start(Xid x, Association a) { |
171 | 172 | throw new UncheckedXAException((XAException) new XAException(XAER_RMERR) |
172 | 173 | .initCause(new NullPointerException("connectionFunction.apply(" + x + ")"))); |
173 | 174 | } |
174 | | - a = new Association(Association.BranchState.ACTIVE, x, c); |
| 175 | + if (!autoCommit(c)) { |
| 176 | + // The Connection is doing work outside of a global transaction, i.e. someone else set its autoCommit status |
| 177 | + // to false before this branch started, so there is work going on outside of the about-to-start branch, so |
| 178 | + // if we were to call commit() on the connection we would have no idea what would be committed. The XA |
| 179 | + // specification calls this "work outside of a global transaction", and says to report XAER_OUTSIDE here in |
| 180 | + // such a case. |
| 181 | + throw new UncheckedXAException((XAException) new XAException(XAER_OUTSIDE) |
| 182 | + .initCause(new IllegalStateException("!c.getAutoCommit(): " + c))); |
| 183 | + } |
| 184 | + a = new Association(Association.BranchState.ACTIVE, |
| 185 | + x, |
| 186 | + false, // not suspended |
| 187 | + c, |
| 188 | + true); // already checked for a false autoCommit status |
175 | 189 | if (LOGGER.isLoggable(Level.FINE)) { |
176 | 190 | LOGGER.logp(Level.FINE, this.getClass().getName(), "start", |
177 | 191 | "Created new Association ({0}) for connection ({1}) in state ACTIVE", new Object[] {a, c}); |
@@ -407,15 +421,18 @@ private XAException convert(XARoutine xaRoutine, Throwable e) { |
407 | 421 | returnValue = (XAException) new XAException(XAER_PROTO).initCause(e); |
408 | 422 | } else if (e instanceof SQLException sqlException) { |
409 | 423 | returnValue = this.exceptionConverter.convert(xaRoutine, sqlException); |
| 424 | + if (returnValue == null) { |
| 425 | + returnValue = (XAException) new XAException(XAER_RMERR).initCause(e); |
| 426 | + } |
410 | 427 | } else if (cause instanceof SQLException sqlException) { |
411 | 428 | returnValue = this.exceptionConverter.convert(xaRoutine, sqlException); |
| 429 | + if (returnValue == null) { |
| 430 | + returnValue = (XAException) new XAException(XAER_RMERR).initCause(e); |
| 431 | + } |
412 | 432 | } else { |
413 | 433 | returnValue = (XAException) new XAException(XAER_RMERR).initCause(e); |
414 | 434 | } |
415 | 435 | } |
416 | | - if (returnValue == null) { |
417 | | - returnValue = (XAException) new XAException(XAER_RMERR).initCause(e); |
418 | | - } |
419 | 436 | return returnValue; |
420 | 437 | } |
421 | 438 |
|
@@ -691,6 +708,14 @@ private static String flagsToString(int flags) { |
691 | 708 | } |
692 | 709 | } |
693 | 710 |
|
| 711 | + private static boolean autoCommit(Connection c) { |
| 712 | + try { |
| 713 | + return c.getAutoCommit(); |
| 714 | + } catch (SQLException e) { |
| 715 | + throw new UncheckedSQLException(e); |
| 716 | + } |
| 717 | + } |
| 718 | + |
694 | 719 |
|
695 | 720 | /* |
696 | 721 | * Inner and nested classes. |
@@ -781,10 +806,6 @@ record Association(BranchState branchState, |
781 | 806 | } |
782 | 807 | */ |
783 | 808 |
|
784 | | - Association(BranchState branchState, Xid xid, Connection connection) { |
785 | | - this(branchState, xid, false, connection, autoCommit(connection)); |
786 | | - } |
787 | | - |
788 | 809 | Association { |
789 | 810 | Objects.requireNonNull(xid, "xid"); |
790 | 811 | boolean autoCommit = false; |
@@ -1059,14 +1080,6 @@ private Association reset() throws SQLException { |
1059 | 1080 | this.priorAutoCommit()); |
1060 | 1081 | } |
1061 | 1082 |
|
1062 | | - private static boolean autoCommit(Connection c) { |
1063 | | - try { |
1064 | | - return c.getAutoCommit(); |
1065 | | - } catch (SQLException e) { |
1066 | | - throw new UncheckedSQLException(e); |
1067 | | - } |
1068 | | - } |
1069 | | - |
1070 | 1083 | // Transaction Branch States (XA specification, table 6-4): |
1071 | 1084 | // S0: Non-existent Transaction |
1072 | 1085 | // S1: Active |
|
0 commit comments