org.firebirdsql.gds.ng.wire.version10.V10InputBlob Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird Show documentation
Show all versions of jaybird Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.gds.ng.wire.version10;
import org.firebirdsql.gds.BlobParameterBuffer;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.impl.wire.XdrOutputStream;
import org.firebirdsql.gds.ng.FbExceptionBuilder;
import org.firebirdsql.gds.ng.LockCloseable;
import org.firebirdsql.gds.ng.listeners.DatabaseListener;
import org.firebirdsql.gds.ng.wire.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import static org.firebirdsql.gds.JaybirdErrorCodes.jb_blobGetSegmentNegative;
import static org.firebirdsql.gds.VaxEncoding.iscVaxInteger2;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.*;
/**
* @author Mark Rotteveel
* @since 3.0
*/
public class V10InputBlob extends AbstractFbWireInputBlob implements FbWireBlob, DatabaseListener {
// TODO V10OutputBlob and V10InputBlob share some common behavior and information (eg in open() and getMaximumSegmentSize()), find a way to unify this
public V10InputBlob(FbWireDatabase database, FbWireTransaction transaction,
BlobParameterBuffer blobParameterBuffer, long blobId) {
super(database, transaction, blobParameterBuffer, blobId);
}
// TODO Need blob specific warning callback?
@Override
public void open() throws SQLException {
try (LockCloseable ignored = withLock()) {
checkDatabaseAttached();
checkTransactionActive();
checkBlobClosed();
final FbWireDatabase database = getDatabase();
try {
final XdrOutputStream xdrOut = database.getXdrStreamAccess().getXdrOut();
final BlobParameterBuffer blobParameterBuffer = getBlobParameterBuffer();
if (blobParameterBuffer == null) {
xdrOut.writeInt(op_open_blob);
} else {
xdrOut.writeInt(op_open_blob2);
xdrOut.writeTyped(blobParameterBuffer);
}
xdrOut.writeInt(getTransaction().getHandle());
xdrOut.writeLong(getBlobId());
xdrOut.flush();
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_write_err).cause(e).toSQLException();
}
try {
final GenericResponse genericResponse = database.readGenericResponse(null);
setHandle(genericResponse.getObjectHandle());
setOpen(true);
resetEof();
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_read_err).cause(e).toSQLException();
}
// TODO Request information on the blob?
} catch (SQLException e) {
exceptionListenerDispatcher.errorOccurred(e);
throw e;
}
}
@Override
public byte[] getSegment(final int sizeRequested) throws SQLException {
try {
if (sizeRequested <= 0) {
throw new FbExceptionBuilder().exception(jb_blobGetSegmentNegative)
.messageParameter(sizeRequested)
.toSQLException();
}
try (LockCloseable ignored = withLock()) {
checkDatabaseAttached();
checkTransactionActive();
checkBlobOpen();
// TODO Is this actually a real limitation, or are larger sizes possible?
int actualSize = 2 + Math.min(sizeRequested, getMaximumSegmentSize());
final GenericResponse response;
final FbWireDatabase database = getDatabase();
try {
final XdrOutputStream xdrOut = database.getXdrStreamAccess().getXdrOut();
xdrOut.writeInt(op_get_segment);
xdrOut.writeInt(getHandle());
xdrOut.writeInt(actualSize);
xdrOut.writeInt(0); // length of segment send buffer (always 0 in get)
xdrOut.flush();
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_write_err).cause(e).toSQLException();
}
try {
response = database.readGenericResponse(null);
// TODO Meaning of 2
if (response.getObjectHandle() == 2) {
// TODO what if I seek on a stream blob?
setEof();
}
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_read_err).cause(e).toSQLException();
}
final byte[] responseBuffer = response.getData();
if (responseBuffer.length == 0) {
return responseBuffer;
}
final ByteArrayOutputStream bos = new ByteArrayOutputStream(actualSize);
int position = 0;
while (position < responseBuffer.length) {
final int segmentLength = iscVaxInteger2(responseBuffer, position);
position += 2;
bos.write(responseBuffer, position, segmentLength);
position += segmentLength;
}
return bos.toByteArray();
}
} catch (SQLException e) {
exceptionListenerDispatcher.errorOccurred(e);
throw e;
}
}
@Override
public void seek(int offset, SeekMode seekMode) throws SQLException {
try (LockCloseable ignored = withLock()) {
checkDatabaseAttached();
checkTransactionActive();
final FbWireDatabase database = getDatabase();
try {
final XdrOutputStream xdrOut = database.getXdrStreamAccess().getXdrOut();
xdrOut.writeInt(op_seek_blob);
xdrOut.writeInt(getHandle());
xdrOut.writeInt(seekMode.getSeekModeId());
xdrOut.writeInt(offset);
xdrOut.flush();
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_write_err).cause(e).toSQLException();
}
try {
database.readResponse(null);
// object handle in response is the current position in the blob (see .NET provider source)
} catch (IOException e) {
throw new FbExceptionBuilder().exception(ISCConstants.isc_net_read_err).cause(e).toSQLException();
}
} catch (SQLException e) {
exceptionListenerDispatcher.errorOccurred(e);
throw e;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy