src.com.ibm.as400.access.JDServerRowCache Maven / Gradle / Ivy
Show all versions of jt400-jdk8 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: JDServerRowCache.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-2001 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.sql.SQLException;
/**
The JDServerRowCache class implements a set of rows that
are generated on the system.
**/
class JDServerRowCache
implements JDRowCache
{
static final String copyright = "Copyright (C) 1997-2001 International Business Machines Corporation and others.";
// Private data.
private int blockingFactor_;
private AS400JDBCResultSet resultSet_; // @D9A Provide warnings to this result set
private AS400JDBCConnection connection_;
private boolean empty_; //empty_ is not cache empty but resultset returning 0 rows "empty"; thats why it is only set once
private boolean emptyChecked_;
private boolean firstBlock_;
private JDServerRow row_;
private int id_;
private boolean lastBlock_;
private DBData serverData_;
private boolean variableFieldCompressionSupported_ = false; //@K54
private int bufferSize_; //@K54
private JDCursor cursor_ = null; //@pda perf2 - fetch/close
private DBReplyRequestedDS fetchReply = null; //@P0A
// Index always points to the row within the cache.
// It is not the row number within the result set.
//
// Cached is the number of rows in the cached block.
//
// When the result set is updatable, it should pass
// in a blocking factor of 1, so that cached_ is
// always equal to 1.
//
private int cached_;
private int index_; //(array index), not row number
// Keep track of the cursor position of the first
// row in the row cache from the front of the
// result. We need to know this to keep the system's
// cursor in sync with the client's cursor. Remember we
// don't know the number of records in the result set so
// moving the cursor based on the end of the rs makes
// us put our local variable back to NOT_KNOWN. We could
// write some messy code to keep track based on end and beginning
// of the RS, but at this time we don't have a requirement
// to do that.
private static int NOT_KNOWN = -9999; // @G1a
private int cursorPositionOfFirstRowInCache_ = NOT_KNOWN; // @G1a //0 means empty cache, 1 means cache is at the beginning (cache 1st row matches host 1st row)
/**
Constructs a row cache assuming that no data has been
prefetched.
@param row The row describing the format.
@param connection The connection to the system.
@param id The id.
@param blockingFactor The blocking factor (in rows).
@param lastBlock Has the last block been fetched?
@param resultSetType The type of result set.
@exception SQLException If an error occurs.
**/
JDServerRowCache (JDServerRow row,
AS400JDBCConnection connection,
int id,
int blockingFactor,
boolean lastBlock, //@PDA perf
int resultSetType)
throws SQLException
{
blockingFactor_ = blockingFactor;
connection_ = connection;
lastBlock_ = lastBlock; //@PDC perf
emptyChecked_ = lastBlock_; //@PDC perf - false unless we are at lastBlock, then true
empty_ = lastBlock_; //@PDA perf
firstBlock_ = true;
id_ = id;
row_ = row;
serverData_ = null;
cached_ = 0;
index_ = -1;
if(connection_.getServerFunctionalLevel() >=14 &&
connection_.getProperties().getBoolean(JDProperties.VARIABLE_FIELD_COMPRESSION) &&
//blockingFactor_ != 1) //@K54 If blocking factor is one, than the result set is scrollable.
resultSetType == java.sql.ResultSet.TYPE_FORWARD_ONLY)
variableFieldCompressionSupported_ = true; //@K54
bufferSize_ = connection_.getProperties().getInt(JDProperties.BLOCK_SIZE); //@K54
// We are before the first row. Actually there is no data in the cache
// when this c'tor is used so it shouldn't make any difference, but
// we will set it to 0 just to be consistent. When an RS is opened
// the cursor is positioned to before the first row, which is what
// 0 means.
cursorPositionOfFirstRowInCache_ = 0; // @G1a
row_.setRowIndex (index_);
}
//@pda perf2
/**
Constructs a row cache assuming that no data has been
prefetched.
@param row The row describing the format.
@param connection The connection to the system.
@param id The id.
@param blockingFactor The blocking factor (in rows).
@param lastBlock Has the last block been fetched?
@param resultSetType The type of result set.
@param JDCursor Cursor associated with rows.
@exception SQLException If an error occurs.
**/
JDServerRowCache (JDServerRow row,
AS400JDBCConnection connection,
int id,
int blockingFactor,
boolean lastBlock,
int resultSetType,
JDCursor cursor)
throws SQLException
{
this(row, connection, id, blockingFactor, lastBlock, resultSetType);
cursor_ = cursor;
}
/**
Constructs a row cache including data that has been
prefetched.
@param row The row describing the format.
@param connection The connection to the system.
@param id The id.
@param blockingFactor Blocking factor (in rows).
@param serverData Prefetched data.
@param lastBlock Has the last block been fetched?
@param resultSetType The type of result set.
@exception SQLException If an error occurs.
**/
JDServerRowCache (JDServerRow row,
AS400JDBCConnection connection,
int id,
int blockingFactor,
DBData serverData,
boolean lastBlock,
int resultSetType)
throws SQLException
{
blockingFactor_ = blockingFactor;
connection_ = connection;
firstBlock_ = true;
id_ = id;
lastBlock_ = lastBlock;
row_ = row;
serverData_ = serverData;
if(connection_.getServerFunctionalLevel() >=14 &&
connection_.getProperties().getBoolean(JDProperties.VARIABLE_FIELD_COMPRESSION) &&
//blockingFactor_ != 1) //@K54 If blocking factor is one, than the result set is scrollable
resultSetType == java.sql.ResultSet.TYPE_FORWARD_ONLY)
variableFieldCompressionSupported_ = true; //@K54
bufferSize_ = connection_.getProperties().getInt(JDProperties.BLOCK_SIZE); //@K54
try
{
cached_ = serverData.getRowCount ();
}
catch (DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
emptyChecked_ = true;
empty_ = (cached_ == 0);
// If we were able to pre-fetch data then the cache starts with the first
// row of data. If we were not able to pre-fetch data then the cache
// is empty.
if (cached_ > 0) // @G1a
cursorPositionOfFirstRowInCache_ = 1; // @G1a
else // @G1a
cursorPositionOfFirstRowInCache_ = 0; // @G1a
index_ = -1;
row_.setRowIndex (index_);
row_.setServerData (serverData_);
}
//@pda perf2
/**
Constructs a row cache including data that has been
prefetched.
@param row The row describing the format.
@param connection The connection to the system.
@param id The id.
@param blockingFactor Blocking factor (in rows).
@param serverData Prefetched data.
@param lastBlock Has the last block been fetched?
@param resultSetType The type of result set.
@param JDCursor Cursor associated with rows.
@exception SQLException If an error occurs.
**/
JDServerRowCache (JDServerRow row,
AS400JDBCConnection connection,
int id,
int blockingFactor,
DBData serverData,
boolean lastBlock,
int resultSetType,
JDCursor cursor)
throws SQLException
{
this(row, connection, id, blockingFactor, serverData, lastBlock, resultSetType);
cursor_ = cursor;
}
/**
Fetches a block of data from the system.
@param fetchScrollOption The fetch scroll option.
@return true if the first or last block (in
the appropriate direction) was fetched,
false otherwise.
@exception SQLException If an error occurs.
**/
private boolean fetch (int fetchScrollOption)
throws SQLException
{
return fetch (fetchScrollOption, 0);
}
/**
Fetches a block of data from the system.
@param fetchScrollOption The fetch scroll option.
@param rows The number of rows when
fetchScrollOption is
DBSQLRequestDS.FETCH_RELATIVE.
@return true if the first or last block (in
the appropriate direction) was fetched,
false otherwise.
@exception SQLException If an error occurs.
**/
private boolean fetch (int fetchScrollOption, int rows)
throws SQLException
{
boolean endBlock = false;
try
{
DBSQLRequestDS request = null; //@P0A
try
{
request = DBDSPool.getDBSQLRequestDS ( //@P0C
DBSQLRequestDS.FUNCTIONID_FETCH,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_RESULT_DATA, 0);
request.setFetchScrollOption (fetchScrollOption, rows);
// If fetching next, then fetch a block. Otherwise,
// just fetch a single row. The check was altered under @G1
// to fetch a block of rows only when we know the cursor
// location. If we don't know the cursor location when we
// get only one row just in case the next request is to
// go backward or relative to the current location. This
// will be slower but it is the only way to assure accurate
// information is returned to the app.
if ((fetchScrollOption == DBSQLRequestDS.FETCH_NEXT) &&
(blockingFactor_ > 0) &&
(cursorPositionOfFirstRowInCache_ >= 0)) // @G1a
{
if(variableFieldCompressionSupported_) //@K54
{
//Do not need to set the blocking factor if using variable-length field compression
//If both the buffer size and blocking factor were set, the buffer size will override
//the blocking factor and the number of rows that will fit in the buffer size will be returned
//regardless of the blocking factor value //@K54
request.setVariableFieldCompression(true); //@K54
request.setBufferSize(bufferSize_ * 1024); //@K54
} //@K54
else //@K54
request.setBlockingFactor (blockingFactor_);
}
else
{
request.setBlockingFactor (1);
}
if (JDTrace.isTraceOn ())
JDTrace.logInformation (connection_, "Fetching a block of data from the system "+fetchScrollOption+","+rows);
if (fetchReply != null) { fetchReply.returnToPool(); fetchReply = null; }
fetchReply = connection_.sendAndReceive (request, id_); //@P0C
int errorClass = fetchReply.getErrorClass();
int returnCode = fetchReply.getReturnCode();
if (((errorClass == 1) && (returnCode == 100))
|| ((errorClass == 2) && (returnCode == 701)))
endBlock = true;
else if((errorClass == 2) && (returnCode == 700)) //@pda perf2 - fetch/close
{
endBlock = true;
if(cursor_ != null)
cursor_.setState(true); //closed cursor already on system
}
// As in AS400JDBCStatement, post a warning if the system gives us a warning,
// otherwise throw an exception
else if (errorClass != 0)
{ // @D1a
// JDError.throwSQLException (connection_, id_, errorClass, returnCode); // @D1d
if (returnCode < 0) { // @D1a
JDError.throwSQLException (this, connection_, id_, errorClass, returnCode); // @D1a
} else { // @D1a
// Post the warning to the resultSet, not the connection @D9A
if (resultSet_ != null) {
resultSet_.postWarning (JDError.getSQLWarning (connection_, id_, errorClass, returnCode)); // @D1a
} else {
if (JDTrace.isTraceOn ()) {
JDTrace.logInformation(connection_, "posting warning to connection");
}
connection_.postWarning (JDError.getSQLWarning (connection_, id_, errorClass, returnCode)); // @D1a
}
}
} // @D1a
// Extract data from the row.
serverData_ = fetchReply.getResultData ();
if (serverData_ == null)
{
endBlock = true; //@rel4 last block was not returned if null???? //@rel9backtotrue and deal with it after called
cached_ = 0;
}
else
{
row_.setServerData (serverData_);
cached_ = serverData_.getRowCount ();
}
if (emptyChecked_ == false) //empty_ is refering to empty resultset, not empty cache_
{
emptyChecked_ = true;
empty_ = (cached_ == 0);
}
}
finally
{
if (request != null) { request.returnToPool(); request =null; }
// if (fetchReply != null) { fetchReply.returnToPool(); fetchReply = null; }
}
}
catch (DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
return endBlock;
}
/**
Sets the fetch size.
@param fetchSize The fetch size.
@exception SQLException If an error occurs.
**/
public void setFetchSize (int fetchSize)
throws SQLException
{
// The fetch size is only used if the "block size" property
// is set to "0".
if (connection_.getProperties ().getInt (JDProperties.BLOCK_SIZE) == 0)
blockingFactor_ = fetchSize;
}
//-------------------------------------------------------------//
// //
// INTERFACE IMPLEMENTATIONS //
// //
//-------------------------------------------------------------//
public void open ()
throws SQLException
{
// No-op. It is assumed here that the cursor is
// already open.
}
public void close ()
throws SQLException
{
// No-op. It is assumed that the cursor will be closed
// elsewhere.
// Make sure reply is returned to pool
if (fetchReply != null) {
fetchReply.returnToPool(); fetchReply = null;
}
}
public void flush ()
throws SQLException
{
cached_ = 0;
emptyChecked_ = false;
}
public void refreshRow ()
throws SQLException
{
fetch (DBSQLRequestDS.FETCH_CURRENT);
index_ = 0;
row_.setRowIndex (index_);
}
public JDRow getRow ()
{
return row_;
}
/**
isEmpty is not cache empty but resultset returning 0 rows "empty"; thats why it is only set once
*/
public boolean isEmpty ()
throws SQLException
{
// If empty has not been checked yet, then no data has
// been fetched. Force the first fetch.
// The change for @G1 makes the code block work (I don't
// think it worked before). For emptyChecked_ to be false
// prefetch must be off. If block size is 0 the beforeFirst()
// call will return 0 rows. The empty flag is set based on how
// many rows are returned so since no rows were returned empty_
// was set to true. The change it to call first to get a row,
// then set the empty_ flag there, if rows are found.
if (emptyChecked_ == false)
{
firstBlock_ = false;
first(true); // @G1a
beforeFirst ();
}
return empty_;
}
public boolean isValid ()
{
return((serverData_ != null)
&& (index_ >= 0)
&& (index_ < cached_));
}
//@abs2 re-design method
/* absolute may or maynot go to server */
public void absolute (int rowNumber)
throws SQLException
{
// If the row is in the cache, then move the index
// withing the cache.
// int newIndex = index_;
//int serverRowIndexFromBeg = cursorPositionOfFirstRowInCache_ + index_; //1 is on first row
//int numberOfServerRows = cursorPositionOfFirstRowInCache_ + cached_ - 1;//!!when lastBlock_==true
if ( (rowNumber >= cursorPositionOfFirstRowInCache_) && (rowNumber < cursorPositionOfFirstRowInCache_+ cached_ )&& (rowNumber >= 0) && (cursorPositionOfFirstRowInCache_ != NOT_KNOWN))
{
//rowNumber is positive and row is in cache_
index_ = rowNumber - cursorPositionOfFirstRowInCache_;
}
else if((rowNumber<0) && lastBlock_ && (cached_ >= -rowNumber) && (cursorPositionOfFirstRowInCache_ != NOT_KNOWN))
{
//rowNumber is negative and row is in cache_
//if lastBlock_ then we know we can just count backwards to the offset in cache_
//(ie if rowNumber is in cache and last row in cache_ is last row on server)
index_ = cached_ + rowNumber;
}
// Otherwise, fetch data from the system. If the
// last block is flagged, then this means the
// request was not valid.
else
{
// Since we could not find the row in the cache we have to find
// it on the system.
absolute(rowNumber, true);
return;
}
row_.setRowIndex (index_);
}
//@abs2
void absolute (int rowNumber, boolean mustAccessServer)
throws SQLException
{
if(mustAccessServer == false)
{
absolute(rowNumber);
return;
}
//int newIndex = rowNumber;
boolean endBlock = false;
if(rowNumber > 0)
{
if(cursor_.isClosed() )//&& !firstBlock_)
{ //@max1
return; //@max1 //can't go and refetch since cursor is closed.
} //@max1
else
{
if(cursor_.getCursorAttributeSensitive() == 0 && cursor_.getCursorAttributeUpdatable() == 0) //@abs3 fix: only use fetch-direct with insensitive read-only cursors
{
endBlock = fetch (DBSQLRequestDS.FETCH_DIRECT, rowNumber);
}
else //@abs3
{ //@abs3
first (true); //@abs3
relative (rowNumber - 1); //@abs3
} //@abs3
}
}
else if(rowNumber == 0)
{
//fetch(direct,0) followed by fetch(relative,-x) does not work
beforeFirst(true);
}
else
{
//hostserver fetch(direct) does not support negative directions
//have to do last() and then reletive(-x)
last (true);
relative (rowNumber + 1);
}
firstBlock_ = false;
if (endBlock == false)
{
index_ = 0;
// @E1D firstBlock_ = false;
lastBlock_ = endBlock;
}
cursorPositionOfFirstRowInCache_ = rowNumber;
row_.setRowIndex (index_);
}
public void afterLast ()
throws SQLException
{
// If the last block is cached, then
// move the index within the cache.
if (lastBlock_)
index_ = cached_;
// Otherwise, change the cursor on the system.
else
{
fetch (DBSQLRequestDS.FETCH_AFTER_LAST);
firstBlock_ = false;
lastBlock_ = true;
index_ = 0;
// We just fetched based on the end of the result set so we no longer
// know the row number of the first row in the cache
cursorPositionOfFirstRowInCache_ = NOT_KNOWN; // @G1a
}
row_.setRowIndex (index_);
}
public void beforeFirst (boolean mustAccessServer)
throws SQLException
{
if(mustAccessServer == false)
{
beforeFirst();
return;
}
else
{
fetch (DBSQLRequestDS.FETCH_BEFORE_FIRST);
firstBlock_ = true;
lastBlock_ = false;
index_ = -1;
// BeforeFirst will not return any rows. Set the
// variable to 0 to indicate we are before the first row.
cursorPositionOfFirstRowInCache_ = 0;
row_.setRowIndex (index_);
}
}
public void beforeFirst ()
throws SQLException
{
// If first block is cached, then move the index
// within the cache.
if (firstBlock_)
index_ = -1;
// Otherwise, change the cursor on the system.
else
{
fetch (DBSQLRequestDS.FETCH_BEFORE_FIRST);
firstBlock_ = true;
lastBlock_ = false;
index_ = -1;
// BeforeFirst will not return any rows. Set the
// variable to 0 to indicate we are before the first row.
cursorPositionOfFirstRowInCache_ = 0; // @G1a
}
row_.setRowIndex (index_);
}
// @G1c
// The logic of this routine was moved to first(boolean). Call the new
// routine saying there is no need to go to the system if the data
// is in the local cache.
public void first ()
throws SQLException
{
first(false);
}
// @G1 new method
void first (boolean mustAccessServer)
throws SQLException
{
// If first block is cached, then move the index
// within the cache (if we are not forced to go to the system).
// @G1 change -- do this only if we attempted to go to the system
// at least once. If we just opened the rs, go to the
// system to see if there are rows in the rs.
boolean done = false; //@rel4
if ((emptyChecked_) && // @G1c
(! mustAccessServer) &&
(firstBlock_))
{ //@rel4
index_ = 0;
done = true; //@rel4
} //@rel4
// Otherwise, change the cursor on the system.
//else //@rel4
if(!done || !isValid()) //@rel4 go to system also if not valid
{
fetch (DBSQLRequestDS.FETCH_FIRST);
firstBlock_ = true;
lastBlock_ = false;
index_ = 0;
// We just fetched based on the beginning of the result set so we
// know the first row in the rs is row 1.
cursorPositionOfFirstRowInCache_ = 1; // @G1a
}
row_.setRowIndex (index_);
}
// @G1
// The logic in this method was moved to last(boolean). Call that
// method saying use data in the cache if the cache has the row
// we need.
public void last ()
throws SQLException
{
last(false);
}
// @G1 new method
void last (boolean mustGoToServer)
throws SQLException
{
// If the last block is cached and contains data, then
// move the index within the cache (if we are not forced to
// go to the system).
if ((lastBlock_) &&
(cached_ > 0) &&
(!mustGoToServer))
index_ = cached_ - 1;
// Otherwise, change the cursor on the system.
else
{
fetch (DBSQLRequestDS.FETCH_LAST);
firstBlock_ = false;
lastBlock_ = true;
index_ = 0;
// We just fetched based on the end of the result set so we no longer
// know the row number of the first row in the cache
cursorPositionOfFirstRowInCache_ = NOT_KNOWN; // @G1a
}
row_.setRowIndex (index_);
}
public void next ()
throws SQLException
{
// If the next row is cached, then move the index
// within the cache.
if (index_ < (cached_ - 1))
++index_;
// If the last block has been fetched,
// then there are no more.
else if (lastBlock_)
index_ = cached_;
// Otherwise, fetch data from the system.
else
{
boolean wasBeforeFirst = (index_== -1) ? true : false; //@rel4
int oldCached = cached_; // @G1a
lastBlock_ = fetch (DBSQLRequestDS.FETCH_NEXT);
firstBlock_ = false;
index_ = 0;
// We get a block of records only when we know the cursor position
// of the first row in the cache. When we know the position, update our
// variable by the number of rows in the cache. (This works
// even when we are getting one row at a time because oldCached will be 1).
if (cursorPositionOfFirstRowInCache_ > 0) // @G1a
cursorPositionOfFirstRowInCache_ = // @G1a
cursorPositionOfFirstRowInCache_ + oldCached; // @G1a
else if(wasBeforeFirst) // @G1a //@rel4 (only set to 1 if wasBeforeFirst)
cursorPositionOfFirstRowInCache_ = 1; // @G1a
else //@rel4
cursorPositionOfFirstRowInCache_ = NOT_KNOWN;//@rel4
}
row_.setRowIndex (index_);
}
public void previous ()
throws SQLException
{
// If the previous row is cached, then move the index
// within the cache.
if (index_ >= 1 && cached_ > 0) //@rel4
--index_;
// If the first block has not been fetched,
// then fetch data from the system.
else if (! firstBlock_)
{
// We did not find the record in the cache so we must be
// on the first record in the cache trying to back up one.
// First move the system's cursor so it is in the correct
// place, then back up one. Having a block of records in
// the cache but not knowing where they came from is a
// "should not occur" error so throw an internal exception.
if (cached_ > 1) // @G1a
{
// @G1a
if (cursorPositionOfFirstRowInCache_ > 0) // @G1a
absolute(cursorPositionOfFirstRowInCache_, true); // @G1a //@abs2
else // @G1a
JDError.throwSQLException (JDError.EXC_INTERNAL); // @G1a
} // @G1a
firstBlock_ = fetch (DBSQLRequestDS.FETCH_PREVIOUS);
lastBlock_ = false;
index_ = cached_ - 1;
if (firstBlock_) // @G1a
cursorPositionOfFirstRowInCache_ = 1; // @G1a
else // @G1a
cursorPositionOfFirstRowInCache_ --; // @G1a
}
// Else we have moved before the first row.
else
index_ = -1;
if(index_ == -1 && cached_ == 0) //@rel4 cache is empty
cursorPositionOfFirstRowInCache_ = 0; //@rel4
row_.setRowIndex (index_);
}
public void relative (int rowNumber)
throws SQLException
{
//boolean wasBeforeFirst = (index_==-1) ? true : false;//@rel4
//boolean wasAfterLast = (wasBeforeFirst == false && lastBlock_ == true && index_ == cached_) ? true : false;//@rel4
// If row number is 0, then don't change the cursor.
if (rowNumber != 0)
{
// If the row is in the cache, then move the index
// withing the cache.
int newIndex = index_ + rowNumber;
if ((newIndex >= 0) && (newIndex < cached_)) //@rel2 allow for before first row //@rel4 -1->0
index_ = newIndex;
else if ((newIndex >= 0) && (newIndex == cached_) && (cursor_.isClosed())) //@max1
index_ = newIndex; //@max1
// Otherwise, fetch data from the system. If the
// last block is flagged, then this means the
// request was not valid.
else
{
// Since we could not find the row in the cache we have to find
// it on the system. First call the system to resync the
// cursor position with what we think it is on the client
// (the local cursor will move if we have a cache hit), then
// the call the system to get data. Note if we have a block
// of records in the cache but do not know where they came
// from, flag an error. That should not happen. We have to
// move the system cursor only if we cached a block of records.
// If only one record is in the cache then the two cursors
// are already in sync.
//Note: relative and absolute call each other, but will not endless-loop since first() always fetches only one row and so cached_=1!
if (cached_ > 1) // @G1a
{
// @G1a
if (cursorPositionOfFirstRowInCache_ > 0) // @G1a
absolute(cursorPositionOfFirstRowInCache_ + index_, true); // @G1a //@abs2
else // @G1a
JDError.throwSQLException (JDError.EXC_INTERNAL); // @G1a
} // @G1a
if(index_ == -1 && cached_ > 0) //@rel2 (if index_ is positioned before any rows, subtract 1 from rowNumber to account that index_ is not on a current row) //@rel4 already set to -1 and added
rowNumber--; //@rel2
else if(index_ == cached_) //@rel3 (if index_ is past the cache_ content, add 1 to rowNumber to account that index_ is not on a current row) //@rel4
rowNumber += index_; //@rel3 //@rel4 even if after last, cursor on host may not know it and may be off by count in cache_
boolean endBlock = fetch (DBSQLRequestDS.FETCH_RELATIVE, rowNumber); //@abs2 comment: why not combine absolutesynchwithserver and fetch using something like fetch(-cache_ + index_ + rowNumber)
firstBlock_ = false; // @E1A
if (endBlock == false)
{
index_ = 0;
// @E1D firstBlock_ = false;
lastBlock_ = endBlock;
}else //@rel4
{ //@rel4
if(rowNumber < 0)//@rel4
{ //@rel4
index_ = -1; //empty //@rel4
cursorPositionOfFirstRowInCache_ = 0; //not aligned
} //@rel4
else //@rel4
cursorPositionOfFirstRowInCache_ = NOT_KNOWN; //@rel4
}
//if ((rowNumber > 0) && (cursorPositionOfFirstRowInCache_ > 0)) // @G1a
if(cursorPositionOfFirstRowInCache_ >=0) //@rel4 if beforefirst also
cursorPositionOfFirstRowInCache_ = // @G1a
cursorPositionOfFirstRowInCache_ + rowNumber; // @G1a
else // @G1a
cursorPositionOfFirstRowInCache_ = NOT_KNOWN; // @G1a
}
}
row_.setRowIndex (index_);
}
protected void finalize() throws Throwable {
super.finalize();
if (fetchReply != null) { fetchReply.returnToPool(); fetchReply=null; }
}
/*
* Set the result set to be used for reporting warnings. @D9A
* This is typically called in the constructor of the result set.
*/
public void setResultSet(AS400JDBCResultSet resultSet) {
resultSet_ = resultSet;
}
}