code: @Override
    public int prepare(Xid xid) throws XAException {
      if (logger.logDebug()) {
        debug("preparing transaction xid = " + xid);
      }
  
      // Check preconditions
      if (!currentXid.equals(xid)) {
        throw new CloudSpannerXAException(CloudSpannerXAException.PREPARE_WITH_SAME,
            Code.UNIMPLEMENTED, XAException.XAER_RMERR);
      }
      if (state != STATE_ENDED) {
        throw new CloudSpannerXAException(CloudSpannerXAException.PREPARE_BEFORE_END,
            Code.FAILED_PRECONDITION, XAException.XAER_INVAL);
      }
  
      state = STATE_IDLE;
      currentXid = null;
  
      try {
        String s = RecoveredXid.xidToString(xid);
        conn.prepareTransaction(s);
        conn.setAutoCommit(localAutoCommitMode);
  
        return XA_OK;
      } catch (CloudSpannerSQLException ex) {
        throw new CloudSpannerXAException(CloudSpannerXAException.ERROR_PREPARING, ex,
            XAException.XAER_RMERR);
      } catch (SQLException ex) {
        throw new CloudSpannerXAException(CloudSpannerXAException.ERROR_PREPARING, ex, Code.UNKNOWN,
            XAException.XAER_RMERR);
      }
    }
docs: Preconditions: 1. xid != null 2. xid is in ended state
  
  Implementation deficiency preconditions: 1. xid was associated with this connection
  
  Postconditions: 1. Transaction is prepared
  
  @see XAResource#prepare(Xid)