Search in sources :

Example 1 with FbStatement

use of org.firebirdsql.gds.ng.FbStatement in project jaybird by FirebirdSQL.

the class TestV10OutputBlob method testUsingCancelledBlob.

/**
 * Test whether a cancelled blob cannot be used (indicating it was indeed cancelled).
 */
@Test
public void testUsingCancelledBlob() throws Exception {
    expectedException.expect(SQLException.class);
    expectedException.expect(allOf(errorCodeEquals(ISCConstants.isc_bad_segstr_id), message(startsWith(getFbMessage(ISCConstants.isc_bad_segstr_id)))));
    final int testId = 1;
    final byte[] baseContent = generateBaseContent();
    final int requiredSize = 256;
    final byte[] testBytes = generateBlobContent(baseContent, requiredSize);
    try (FbWireDatabase db = createDatabaseConnection()) {
        final SimpleStatementListener listener = new SimpleStatementListener();
        final FbTransaction transaction = getTransaction(db);
        try {
            final FbStatement statement = db.createStatement(transaction);
            statement.addStatementListener(listener);
            final FbBlob blob = db.createBlobForOutput(transaction, null);
            blob.open();
            int bytesWritten = 0;
            while (bytesWritten < testBytes.length) {
                // TODO the interface for writing blobs should be simpler
                byte[] buffer = new byte[Math.min(blob.getMaximumSegmentSize(), testBytes.length - bytesWritten)];
                System.arraycopy(testBytes, bytesWritten, buffer, 0, buffer.length);
                blob.putSegment(buffer);
                bytesWritten += buffer.length;
            }
            blob.cancel();
            statement.prepare(INSERT_BLOB_TABLE);
            final DatatypeCoder datatypeCoder = db.getDatatypeCoder();
            FieldValue param1 = new FieldValue(datatypeCoder.encodeInt(testId));
            FieldValue param2 = new FieldValue(datatypeCoder.encodeLong(blob.getBlobId()));
            statement.execute(RowValue.of(param1, param2));
            statement.close();
        } finally {
            transaction.commit();
        }
    }
}
Also used : SimpleStatementListener(org.firebirdsql.gds.ng.wire.SimpleStatementListener) DatatypeCoder(org.firebirdsql.gds.ng.DatatypeCoder) FieldValue(org.firebirdsql.gds.ng.fields.FieldValue) FbStatement(org.firebirdsql.gds.ng.FbStatement) FbWireDatabase(org.firebirdsql.gds.ng.wire.FbWireDatabase) FbTransaction(org.firebirdsql.gds.ng.FbTransaction) FbBlob(org.firebirdsql.gds.ng.FbBlob) Test(org.junit.Test)

Example 2 with FbStatement

use of org.firebirdsql.gds.ng.FbStatement in project jaybird by FirebirdSQL.

the class V10Database method createStatement.

@Override
public final FbStatement createStatement(FbTransaction transaction) throws SQLException {
    try {
        checkAttached();
        final FbStatement stmt = protocolDescriptor.createStatement(this);
        stmt.addExceptionListener(exceptionListenerDispatcher);
        stmt.setTransaction(transaction);
        return stmt;
    } catch (SQLException ex) {
        exceptionListenerDispatcher.errorOccurred(ex);
        throw ex;
    }
}
Also used : SQLException(java.sql.SQLException) FbStatement(org.firebirdsql.gds.ng.FbStatement)

Example 3 with FbStatement

use of org.firebirdsql.gds.ng.FbStatement in project jaybird by FirebirdSQL.

the class FBManagedConnectionFactory method tryCompleteInLimboTransaction.

/**
 * Try to complete the "in limbo" transaction. This method tries to
 * reconnect an "in limbo" transaction and complete it either by commit or
 * rollback. If no "in limbo" transaction can be found, or error happens
 * during completion, an exception is thrown.
 *
 * @param xid
 *            Xid of the transaction to reconnect.
 * @param commit
 *            <code>true</code> if "in limbo" transaction should be
 *            committed, otherwise <code>false</code>.
 *
 * @throws XAException
 *             if "in limbo" transaction cannot be completed.
 */
private void tryCompleteInLimboTransaction(Xid xid, boolean commit) throws XAException {
    try {
        FBManagedConnection tempMc = null;
        FirebirdLocalTransaction tempLocalTx = null;
        try {
            tempMc = new FBManagedConnection(null, null, this);
            tempLocalTx = (FirebirdLocalTransaction) tempMc.getLocalTransaction();
            tempLocalTx.begin();
            long fbTransactionId = 0;
            boolean found = false;
            if (tempMc.getGDSHelper().compareToVersion(2, 0) < 0) {
                // Find Xid by scanning
                FBXid[] inLimboIds = (FBXid[]) tempMc.recover(XAResource.TMSTARTRSCAN);
                for (FBXid inLimboId : inLimboIds) {
                    if (inLimboId.equals(xid)) {
                        found = true;
                        fbTransactionId = inLimboId.getFirebirdTransactionId();
                    }
                }
            } else {
                // Find Xid by intelligent scan
                FBXid foundXid = (FBXid) tempMc.findSingleXid(xid);
                if (foundXid != null && foundXid.equals(xid)) {
                    found = true;
                    fbTransactionId = foundXid.getFirebirdTransactionId();
                }
            }
            if (!found) {
                throw new FBXAException((commit ? "Commit" : "Rollback") + " called with unknown transaction.", XAException.XAER_NOTA);
            }
            FbDatabase dbHandle = tempMc.getGDSHelper().getCurrentDatabase();
            FbTransaction trHandle = dbHandle.reconnectTransaction(fbTransactionId);
            // complete transaction by commit or rollback
            if (commit) {
                trHandle.commit();
            } else {
                trHandle.rollback();
            }
            if (tempMc.getGDSHelper().compareToVersion(3, 0) < 0) {
                // remove heuristic data from rdb$transactions (only possible in versions before Firebird 3)
                try {
                    String query = "delete from rdb$transactions where rdb$transaction_id = " + fbTransactionId;
                    GDSHelper gdsHelper = new GDSHelper(dbHandle);
                    FbTransaction trHandle2 = dbHandle.startTransaction(getDefaultTpb().getTransactionParameterBuffer());
                    gdsHelper.setCurrentTransaction(trHandle2);
                    FbStatement stmtHandle2 = dbHandle.createStatement(trHandle2);
                    stmtHandle2.prepare(query);
                    stmtHandle2.execute(RowValue.EMPTY_ROW_VALUE);
                    stmtHandle2.close();
                    trHandle2.commit();
                } catch (SQLException sqle) {
                    throw new FBXAException("unable to remove in limbo transaction from rdb$transactions where rdb$transaction_id = " + fbTransactionId, XAException.XAER_RMERR);
                }
            }
        } catch (SQLException ex) {
            /*
                 * if ex.getIntParam() is 335544353 (transaction is not in limbo) and next ex.getIntParam() is 335544468 (transaction {0} is {1})
                 *  => detected heuristic
                 */
            // TODO: We may need to parse the exception to get the details (or we need to handle this specific one differently)
            int errorCode = XAException.XAER_RMERR;
            int sqlError = ex.getErrorCode();
            if (sqlError == ISCConstants.isc_no_recon) /*&& nextIntParam == ISCConstants.isc_tra_state*/
            {
                if (ex.getMessage().contains("committed")) {
                    errorCode = XAException.XA_HEURCOM;
                } else if (ex.getMessage().contains("rolled back")) {
                    errorCode = XAException.XA_HEURCOM;
                }
            }
            throw new FBXAException("unable to complete in limbo transaction", errorCode, ex);
        } finally {
            try {
                if (tempLocalTx != null && tempLocalTx.inTransaction())
                    tempLocalTx.commit();
            } finally {
                if (tempMc != null)
                    tempMc.destroy();
            }
        }
    } catch (ResourceException ex) {
        throw new FBXAException(XAException.XAER_RMERR, ex);
    }
}
Also used : SQLException(java.sql.SQLException) GDSHelper(org.firebirdsql.gds.impl.GDSHelper) ResourceException(javax.resource.ResourceException) FbStatement(org.firebirdsql.gds.ng.FbStatement) FbDatabase(org.firebirdsql.gds.ng.FbDatabase) FbTransaction(org.firebirdsql.gds.ng.FbTransaction)

Aggregations

FbStatement (org.firebirdsql.gds.ng.FbStatement)3 SQLException (java.sql.SQLException)2 FbTransaction (org.firebirdsql.gds.ng.FbTransaction)2 ResourceException (javax.resource.ResourceException)1 GDSHelper (org.firebirdsql.gds.impl.GDSHelper)1 DatatypeCoder (org.firebirdsql.gds.ng.DatatypeCoder)1 FbBlob (org.firebirdsql.gds.ng.FbBlob)1 FbDatabase (org.firebirdsql.gds.ng.FbDatabase)1 FieldValue (org.firebirdsql.gds.ng.fields.FieldValue)1 FbWireDatabase (org.firebirdsql.gds.ng.wire.FbWireDatabase)1 SimpleStatementListener (org.firebirdsql.gds.ng.wire.SimpleStatementListener)1 Test (org.junit.Test)1