com.ibm.as400.access.JDLobLocator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400 Show documentation
Show all versions of jt400 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: JDLobLocator.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2003 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.sql.SQLException;
/**
* The JDLobLocator class provides access to large objects via a locator.
**/
//
// Implementation note:
//
// LOBs were 15MB max until an OS/400 V5R2 PTF, when they became
// 2GB max. This is OK, since the size can still be stored in a Java int
// without worrying about the sign.
//
// Note: A "LOB-character" refers to a one-byte value in the case of a BLOB or CLOB,
// and a two-byte value in the case of a DBCLOB.
//
class JDLobLocator
{
private AS400JDBCConnection connection_;
private boolean dataCompression_;
private int id_;
private int handle_ = -1;
private long length_ = -1; // The current length in LOB-characters.
private int maxLength_; // The max length in LOB-characters.
private int columnIndex_ = -1;
private boolean graphic_;
DBReplyRequestedDS retrieveDataReply = null;
/**
* Constructs an JDLobLocator object.
* @param connection The connection to the system.
* @param id The correlation ID used for any subsequent LOB datastreams (@CRS - why is this here?).
* @param maxLength The max length in bytes on the system.
**/
JDLobLocator(AS400JDBCConnection connection, int id, int maxLength, boolean graphic)
{
connection_ = connection;
id_ = id;
maxLength_ = maxLength;
dataCompression_ = connection_.getDataCompression() == AS400JDBCConnection.DATA_COMPRESSION_OLD_;
graphic_ = graphic;
}
// This is used by the SQLLocator classes to clone the locator so that the internal
// copy of the locator (that gets reused) does not get handed to the user. If that
// were to happen, the next time a statement went to update the locator object with
// a new handle id, the user's locator would all of a sudden be pointing to the
// wrong data on the system.
JDLobLocator(JDLobLocator loc)
{
connection_ = loc.connection_;
id_ = loc.id_;
maxLength_ = loc.maxLength_;
dataCompression_ = loc.dataCompression_;
graphic_ = loc.graphic_;
handle_ = loc.handle_;
length_ = loc.length_;
columnIndex_ = loc.columnIndex_;
}
/**
* Returns the locator handle.
* @return The locator handle, or -1 if not set.
**/
synchronized int getHandle()
{
return handle_;
}
/**
* Returns the length of this LOB in LOB-characters (the length returned from the system).
* For BLOBs and CLOBs (single/mixed) this is the same as the number of bytes.
* For DBCLOBs, this is half the number of bytes.
**/
synchronized long getLength() throws SQLException
{
if (length_ < 0) // Re-retrieve it.
{
try
{
DBSQLRequestDS request = null;
DBReplyRequestedDS getLengthReply = null;
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_RETRIEVE_LOB_DATA,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_RESULT_DATA, 0);
request.setLOBLocatorHandle(handle_);
request.setRequestedSize(0);
request.setStartOffset(0);
request.setCompressionIndicator(dataCompression_ ? 0xF1 : 0xF0);
request.setReturnCurrentLengthIndicator(0xF1);
if (columnIndex_ != -1)
{
request.setColumnIndex(columnIndex_);
}
getLengthReply = connection_.sendAndReceive(request, id_); //@CRS: Why are we reusing the correlation ID here?
int errorClass = getLengthReply.getErrorClass();
int returnCode = getLengthReply.getReturnCode();
if (errorClass != 0)
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
length_ = getLengthReply.getCurrentLOBLength();
}
finally
{
if (request != null) { request.returnToPool(); request =null; }
if (getLengthReply != null) { getLengthReply.returnToPool(); getLengthReply=null; } // Note: No portion of this reply is cached, so it can be returned to the pool
}
}
catch (DBDataStreamException e)
{
JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
}
}
return length_;
}
/**
* Returns the max size of this locator column in LOB-characters.
**/
int getMaxLength()
{
return maxLength_;
}
/**
Retrieves part of the contents of the lob.
@param offset The offset within the LOB, in LOB-characters.
@param length The number of LOB-characters to read from the LOB.
@return The contents.
@exception SQLException If the position is not valid,
if the length is not valid,
or an error occurs.
**/
synchronized DBLobData retrieveData(long offset, int length) throws SQLException
{
if (offset < 0 || length < 0) JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
if (offset >= getMaxLength()) JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
// The DB host server currently only supports 4-byte integers for length and offset on the request.
if (offset > 0x7FFFFFFF) offset = 0x7FFFFFFF;
try
{
DBSQLRequestDS request = null;
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_RETRIEVE_LOB_DATA,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_RESULT_DATA, 0);
request.setLOBLocatorHandle(handle_);
request.setRequestedSize(length);
request.setStartOffset((int)offset); // Some day the IBM i will support 8-byte offsets.
request.setCompressionIndicator(dataCompression_ ? 0xF1 : 0xF0);
request.setReturnCurrentLengthIndicator(0xF1);
// If a column index has not been set for this locator, then do not pass
// the optional column index parameter to the system.
if (columnIndex_ != -1)
{
request.setColumnIndex(columnIndex_);
}
if (JDTrace.isTraceOn())
{
JDTrace.logInformation(connection_, "Retrieving lob data from handle: " + handle_ +
" bytesToRead: " + length + " startingOffset: " + offset +
" dataCompression: " + dataCompression_ + " columnIndex: " + columnIndex_);
}
if (retrieveDataReply != null) { retrieveDataReply.returnToPool(); retrieveDataReply=null; }
retrieveDataReply = connection_.sendAndReceive(request, id_);
int errorClass = retrieveDataReply.getErrorClass();
int returnCode = retrieveDataReply.getReturnCode();
if (errorClass != 0) JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
length_ = retrieveDataReply.getCurrentLOBLength();
DBLobData lobData = retrieveDataReply.getLOBData();
if (graphic_)
{
lobData.adjustForGraphic();
}
return lobData;
}
finally
{
if (request != null) { request.returnToPool(); request =null; }
// Cannot return this to the pool because the data_ array is now part of lobData
// if (retrieveDataReply != null) { retrieveDataReply.returnToPool(); retrieveDataReply = null; }
}
}
catch (DBDataStreamException e)
{
JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
return null;
}
}
/**
Sets the column index.
@param handle The column index.
**/
void setColumnIndex(int columnIndex)
{
columnIndex_ = columnIndex;
}
/**
Sets the locator handle.
@param handle The locator handle.
**/
synchronized void setHandle(int handle)
{
handle_ = handle;
length_ = -1;
}
int writeData(long offset, byte data, boolean truncate) throws SQLException //@K1C
{
return writeData(offset, new byte[] { data}, 0, 1, truncate); //@K1C
}
int writeData(long offset, byte[] data, boolean truncate) throws SQLException //@K1C
{
return writeData(offset, data, 0, data.length, truncate); //@k1C
}
/**
Writes part of the contents of the lob.
@param lobOffset The offset (in LOB-characters) within the lob.
@param data The data to write.
@param offset The offset into the byte array from which to copy data.
@param length The number of bytes out of the byte array to write.
@exception SQLException If the position is not valid,
if the length is not valid,
or an error occurs.
**/
synchronized int writeData(long lobOffset, byte[] data, int offset, int length, boolean truncate) throws SQLException //@K1C
{
if (data == null) throw new NullPointerException("data");
if ((lobOffset < 0) || (length < 0)) JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
// The DB host server currently only supports 4-byte integers for the offset on the request.
// Note that we can keep the length as a 4-byte integer because Java does not support
// using a long as a byte[] index, so the most data we could ever send at a time would
// be 2 GB.
if (lobOffset > 0x7FFFFFFF) lobOffset = 0x7FFFFFFF;
// If we are a DBCLOB, the data in the byte array is already double-byte data,
// but we need to tell the system that the number of characters we're writing is
// half of that (that is, we need to tell it the number of LOB-characters).
// The lobOffset is still the right offset, in terms of LOB-characters.
int lengthToUse = graphic_ ? length / 2 : length;
try
{
DBSQLRequestDS request = null;
DBReplyRequestedDS writeDataReply = null;
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_WRITE_LOB_DATA,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_RESULT_DATA, 0);
request.setLobTruncation(truncate); //Do not truncate @K1A
request.setLOBLocatorHandle(handle_);
request.setRequestedSize(lengthToUse);
request.setStartOffset((int)lobOffset); // Some day the IBM i will support 8-byte offsets.
request.setCompressionIndicator(0xF0); // No compression for now.
request.setLOBData(data, offset, length);
if (JDTrace.isTraceOn())
{
JDTrace.logInformation(connection_, "Writing lob data to handle: " + handle_ + " offset: " + lobOffset + " length: " + length);
}
writeDataReply = connection_.sendAndReceive(request, id_);
int errorClass = writeDataReply.getErrorClass();
int returnCode = writeDataReply.getReturnCode();
if (errorClass != 0)
{
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
}
length_ = -1; //@CRS - We could probably re-calculate it, but for now, we force another call to the system.
return length;
}
finally
{
if (request != null) { request.returnToPool(); request =null; }
// Can be returned immediately
if (writeDataReply != null) { writeDataReply.returnToPool(); writeDataReply= null; }
}
}
catch (DBDataStreamException e)
{
JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
}
return -1;
}
boolean isGraphic()
{
return graphic_;
}
//@xmlgraphic
void setGraphic(boolean isGraphic)
{
graphic_ = isGraphic;
}
//@pda 550
/**
* Free up resource for this lob locator on host server.
**/
synchronized void free() throws SQLException
{
if(connection_.getVRM() < JDUtilities.vrm610 ) //@ns1
{ //@ns1
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED); //@ns1
return; //@ns1
} //@ns1
DBSQLRequestDS request = null;
DBReplyRequestedDS freeReply = null;
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_FREE_LOB, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA, 0);
request.setLOBLocatorHandle(handle_);
// request.setRequestedSize(0); //@pdd
// request.setStartOffset(0); //@pdd
// request.setCompressionIndicator(dataCompression_ ? 0xF1 : 0xF0); //@pdd
//if (columnIndex_ != -1) //@pdd
// { //@pdd
// request.setColumnIndex(columnIndex_); //@pdd
// } //@pdd
freeReply = connection_.sendAndReceive(request, id_);
// int errorClass = freeReply.getErrorClass();
// int returnCode = freeReply.getReturnCode();
//7,-401 signals already free
//if (errorClass != 0 && !(errorClass == 7 && returnCode == -401))
//JDError.throwSQLException(this, connection_, id_, errorClass, returnCode); //@free2 hostnow has various errors if locator is already freed.
// In free, if the retrieveDataReply is set, then return it to the pool
if (retrieveDataReply != null) {
retrieveDataReply.returnToPool();retrieveDataReply = null;
}
} catch (DBDataStreamException e)
{
JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
}finally
{
if (request != null) {
request.returnToPool(); request =null;
}
if (freeReply != null) { freeReply.returnToPool(); freeReply = null; }
}
}
protected void finalize() throws Throwable {
super.finalize();
if (retrieveDataReply != null) {
retrieveDataReply.returnToPool();retrieveDataReply = null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy