/** * Preconditions: 1. xid must be in prepared state in the server * * <p>Implementation deficiency preconditions: 1. Connection must be in idle state * * <p>Postconditions: 1. Transaction is committed */ private void commitPrepared(Xid xid) throws XAException { try { // Check preconditions. The connection mustn't be used for another // other XA or local transaction, or the COMMIT PREPARED command // would mess it up. if (state != STATE_IDLE || conn.getTransactionState() != ProtocolConnection.TRANSACTION_IDLE) throw new PGXAException( GT.tr("Not implemented: 2nd phase commit must be issued using an idle connection"), XAException.XAER_RMERR); String s = RecoveredXid.xidToString(xid); localAutoCommitMode = conn.getAutoCommit(); conn.setAutoCommit(true); Statement stmt = conn.createStatement(); try { stmt.executeUpdate("COMMIT PREPARED '" + s + "'"); } finally { stmt.close(); conn.setAutoCommit(localAutoCommitMode); } } catch (SQLException ex) { throw new PGXAException( GT.tr("Error committing prepared transaction"), ex, XAException.XAER_RMERR); } }
/** * Preconditions: 1. xid is known to the RM or it's in prepared state * * <p>Implementation deficiency preconditions: 1. xid must be associated with this connection if * it's not in prepared state. * * <p>Postconditions: 1. Transaction is rolled back and disassociated from connection */ public void rollback(Xid xid) throws XAException { if (logger.logDebug()) debug("rolling back xid = " + xid); // We don't explicitly check precondition 1. try { if (currentXid != null && xid.equals(currentXid)) { state = STATE_IDLE; currentXid = null; conn.rollback(); conn.setAutoCommit(localAutoCommitMode); } else { String s = RecoveredXid.xidToString(xid); conn.setAutoCommit(true); Statement stmt = conn.createStatement(); try { stmt.executeUpdate("ROLLBACK PREPARED '" + s + "'"); } finally { stmt.close(); } } } catch (SQLException ex) { throw new PGXAException( GT.tr("Error rolling back prepared transaction"), ex, XAException.XAER_RMERR); } }
/** * Preconditions: 1. xid must in ended state. * * <p>Implementation deficiency preconditions: 1. this connection must have been used to run the * transaction * * <p>Postconditions: 1. Transaction is committed */ private void commitOnePhase(Xid xid) throws XAException { try { // Check preconditions if (currentXid == null || !currentXid.equals(xid)) { // In fact, we don't know if xid is bogus, or if it just wasn't associated with this // connection. // Assume it's our fault. throw new PGXAException( GT.tr( "Not implemented: one-phase commit must be issued using the same connection that was used to start it"), XAException.XAER_RMERR); } if (state != STATE_ENDED) throw new PGXAException(GT.tr("commit called before end"), XAException.XAER_PROTO); // Preconditions are met. Commit state = STATE_IDLE; currentXid = null; conn.commit(); conn.setAutoCommit(localAutoCommitMode); } catch (SQLException ex) { throw new PGXAException(GT.tr("Error during one-phase commit"), ex, XAException.XAER_RMERR); } }
/** * Preconditions: 1. flags must be one of TMNOFLAGS, TMRESUME or TMJOIN 2. xid != null 3. * connection must not be associated with a transaction 4. the TM hasn't seen the xid before * * <p>Implementation deficiency preconditions: 1. TMRESUME not supported. 2. if flags is TMJOIN, * we must be in ended state, and xid must be the current transaction 3. unless flags is TMJOIN, * previous transaction using the connection must be committed or prepared or rolled back * * <p>Postconditions: 1. Connection is associated with the transaction */ public void start(Xid xid, int flags) throws XAException { if (logger.logDebug()) debug("starting transaction xid = " + xid); // Check preconditions if (flags != XAResource.TMNOFLAGS && flags != XAResource.TMRESUME && flags != XAResource.TMJOIN) throw new PGXAException(GT.tr("Invalid flags"), XAException.XAER_INVAL); if (xid == null) throw new PGXAException(GT.tr("xid must not be null"), XAException.XAER_INVAL); if (state == STATE_ACTIVE) throw new PGXAException( GT.tr("Connection is busy with another transaction"), XAException.XAER_PROTO); // We can't check precondition 4 easily, so we don't. Duplicate xid will be catched in prepare // phase. // Check implementation deficiency preconditions if (flags == TMRESUME) throw new PGXAException(GT.tr("suspend/resume not implemented"), XAException.XAER_RMERR); // It's ok to join an ended transaction. WebLogic does that. if (flags == TMJOIN) { if (state != STATE_ENDED) throw new PGXAException( GT.tr("Transaction interleaving not implemented"), XAException.XAER_RMERR); if (!xid.equals(currentXid)) throw new PGXAException( GT.tr("Transaction interleaving not implemented"), XAException.XAER_RMERR); } else if (state == STATE_ENDED) throw new PGXAException( GT.tr("Transaction interleaving not implemented"), XAException.XAER_RMERR); try { localAutoCommitMode = conn.getAutoCommit(); conn.setAutoCommit(false); } catch (SQLException ex) { throw new PGXAException(GT.tr("Error disabling autocommit"), ex, XAException.XAER_RMERR); } // Preconditions are met, Associate connection with the transaction state = STATE_ACTIVE; currentXid = xid; }
/** * Preconditions: 1. xid != null 2. xid is in ended state * * <p>Implementation deficiency preconditions: 1. xid was associated with this connection * * <p>Postconditions: 1. Transaction is prepared */ public int prepare(Xid xid) throws XAException { if (logger.logDebug()) debug("preparing transaction xid = " + xid); // Check preconditions if (!currentXid.equals(xid)) { throw new PGXAException( GT.tr( "Not implemented: Prepare must be issued using the same connection that started the transaction"), XAException.XAER_RMERR); } if (state != STATE_ENDED) throw new PGXAException(GT.tr("Prepare called before end"), XAException.XAER_INVAL); state = STATE_IDLE; currentXid = null; if (!conn.haveMinimumServerVersion("8.1")) throw new PGXAException( GT.tr("Server versions prior to 8.1 do not support two-phase commit."), XAException.XAER_RMERR); try { String s = RecoveredXid.xidToString(xid); Statement stmt = conn.createStatement(); try { stmt.executeUpdate("PREPARE TRANSACTION '" + s + "'"); } finally { stmt.close(); } conn.setAutoCommit(localAutoCommitMode); return XA_OK; } catch (SQLException ex) { throw new PGXAException(GT.tr("Error preparing transaction"), ex, XAException.XAER_RMERR); } }