All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.JDServerRowCache Maven / Gradle / Ivy

There is a newer version: 20.0.7
Show newest version
///////////////////////////////////////////////////////////////////////////////
//                                                                             
// 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy