src.com.ibm.as400.access.DBVariableData Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk8 Show documentation
Show all versions of jt400-jdk8 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//JTOpen (IBM Toolbox for Java - OSS version)
//Filename: DBVariableDataInput.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) 2009-2009 International Business Machines Corporation and
//others. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
//@array new class
/**
An implementation of DBData which
describes the data used in datastreams for (the release following v6r1) and later
systems when sending arrays as input to stored procedures.
This is the implementation of the x382f and x3901 codepoints.
Since input and output are different, we have toHost and fromHost member data.
Output data from host is received in one byte array, which we parse and save various offsets for later use.
Input data size of header, indicators, data is calculated externally and passed in to constructor.
Before arrays, input/output parms for stored procedures were handled with codepoints x381f and x380e via DBExtendedData.
If an input or output parm is an array, then we use x382f and x3901 codepoints instead.
Note: This class is modeled after DBExtendedData since (x382F is like x381f and x3901 is like x380e codepoints)
382f (input parms):
Consistency token 4 bytes
Count of '9911'x and '9912'x code points that follow 2 bytes
'9911'x , data type 2 bytes, data length 4 bytes, # of data items 4 bytes
'9912'x , data type 2 bytes, data length 4 bytes
all of the indicator data
all of the data bytes
3901 (output parms):
Consistency token 4 bytes
Row Count 4 bytes
Column Count 2 bytes
Indicator Size 2 bytes
RESERVED 4 bytes
Row Size 4 bytes
Consistency token 4 bytes
Count of '9911'x and '9912'x code points that follow 2 bytes
'9911'x , data type 2 bytes, data length 4 bytes, # of data items 4 bytes
'9912'x , data type 2 bytes, data length 4 bytes
all of the indicator data
all of the data bytes
NOTE 1: Clients will only receive the information about output parameters. If a stored procedure is called with 3 IN and 2 OUT/INOUT parameters(in any order), the count of parameters returned on this flow is 2, followed by the indicator and data for those 2 OUT/INOUT parameters.
NOTE 2: When returning a NULL array, ZDA will pass '9911'x followed by 'FFFF'x.
*/
class DBVariableData
implements DBData
{
private static final String copyright = "Copyright (C) 1997-2001 International Business Machines Corporation and others.";
// Private data.
private byte[] rawBytes_ = null; //will be all data combined when sending in request and receiveing data
private int headerCurOffsetToHost_ = -1; //index into rawBytes_[] (toHost)
private int indicatorCurOffsetToHost_ = -1; //index into rawBytesIndicatorsToHost_[]
private int dataCurOffsetToHost_ = -1; //index into rawBytesDataToHost_[] (may not be used since we call SQLData.convertToRawBytes externally which tracks this offset)
private int headerTotalSizeToHost_ = -1; //length for rawBytesToHost_ when sending to host (could be smaller if null arrays etc)
//block size starting from count of 9911/9912s up to indicators (not consistency token etc)
private int indicatorTotalSizeToHost_ = -1; //length for rawBytesIndicatorsToHost_
private int dataTotalSizeToHost_ = -1; //length for rawBytesDataToHost_ when sending to host
private int offset_ = -1; //
//This was for pre-V5R1 private boolean dataCompressed_ = false; (old pre-ILE compression)
//Also note: ILE compression is done outside this class on whole stream
private boolean vlfCompressed_ = false; //For now, not supported in arrays
private int rowCount_ = -1; //for now, only 1 row
private int columnCount_ = -1;
private int indicatorSize_ = -1;
//now always variable private int rowSize_ = -1;
//for input parms, offset_, add +4 to get to count of parms.
//for output parms, here, we addjust +4 to get to begining of array data (count of parms)
final private int actual382fInArrayStart_ = 4;
final private int actual3901OutArrayStart_ = 4; //@arraylen
private int headerOffsetFromHost_ = -1; //same as offset_, but a user-friendly name
private int indicatorOffsetFromHost_ = -1;
private int dataOffsetFromHost_ = -1;
private int lengthFromHost_ = -1; //Total length of x382f/x3901 (header/indicators/data)
//Four parallel arrays below are generated to maintain header, indicator, data offset info from a reply from the Host.
//These four arrays are all 0 offset based. So you will have to add values in them to headerOffsetFromHost_ or dataOffsetFromHost_ when used
//This is because data are variable depending upon the number/type of columns etc
//Instead of making JDServerRow more messy than it already is, adding these four parallel arrays here
private int[] indicatorOffsetsFromHost_ = null; //@array
private int[] dataOffsetsFromHost_ = null; //@array
private int[] indicatorCountsFromHost_ = null; //@array number of indicators for a given column (1 if non-array, else array length)
private int[] totalDataLengthsFromHost_ = null; //@array total length of data portion in stream
private int[] arrayDataLengthsFromHost_ = null; //@array length of each data element in array
private int[] dataIsArrayFromHost_ = null; //@nullelem flag 1 = array 0 = non-array
private int[] dataIsNullArrayFromHost_ = null; //@nullelem flag -1 = null array 0 = non null
/**
Constructs a DBVariableData object. Use this when overlaying
on a reply datastream. The cached data will be set when overlay()
is called.
**/
public DBVariableData ()
{
//@array nothing to do. overlay will calculate offsets etc.
}
/**
Constructs a DBVariableData object. Use this when overlaying
on a request datastream. This sets the cached data so that
the total length can be calculated before calling overlay().
* @param columnCount
* @param indicatorSize
* @param headerTotalSize
* @param indicatorTotalSize
* @param dataTotalSize
* @throws DBDataStreamException If there is an error in the datastream.
**/
public DBVariableData (
int columnCount,
int indicatorSize,
int headerTotalSize,
int indicatorTotalSize,
int dataTotalSize)
throws DBDataStreamException
{
//input parm constructor
rowCount_ = 1; //always 1 row when sending array
columnCount_ = columnCount;
indicatorSize_ = 2; //always 2 for now
headerTotalSizeToHost_ = headerTotalSize;
indicatorTotalSizeToHost_ = indicatorTotalSize;
dataTotalSizeToHost_ = dataTotalSize;
}
/**
Positions the overlay structure. This reads the cached data only
when it was not previously set by the constructor.
**/
public void overlay (byte[] rawBytes, int offset)
{
if (rowCount_ == -1) {
//output array
offset_ = offset;
lengthFromHost_ = 0; //Total length of x3901 (header/indicators/data)
//Header is also variable depending on number of columns and whether they are arrays/nulls etc.
int headerLength = 0; //(consistency=4, count=2, x9911/x9912 blocks)
//on reply stream, we only need one array rawBytes_[] since host already assembled it.
//ouput 3901: useful data starts at offset 20, not 4 like input.
columnCount_ = BinaryConverter.byteArrayToShort(rawBytes, offset_ + actual3901OutArrayStart_); //count of 9911s or 9912s
rowCount_ = 1; //always 1 row
indicatorSize_ = 2; //always 2 bytes
indicatorOffsetsFromHost_ = new int[columnCount_]; //one per column
indicatorCountsFromHost_ = new int[columnCount_]; //one per column - number of indicators for a given column
dataOffsetsFromHost_ = new int[columnCount_]; //one per column
totalDataLengthsFromHost_ = new int[columnCount_]; //one per column
arrayDataLengthsFromHost_ = new int[columnCount_]; //one per column @G2A
dataIsArrayFromHost_ = new int[columnCount_]; //one per column //@nullelem
dataIsNullArrayFromHost_ = new int[columnCount_]; //one per column //@nullelem
//iterate through columns to get total length of data and indicators
//colDescs used to iterate through each of the 9911/9912 col descriptions.
int colDescs = offset_ + actual3901OutArrayStart_ + 2; //start of first col description: offset + 4 + 2 (# of 9911 and 9912 descriptors)
int dataLenAll = 0;
int indicatorLenAll = 0;
for(int i = 0; i < columnCount_; i++){
short descType = BinaryConverter.byteArrayToShort(rawBytes, colDescs); //9911=array or 9912=non-array
if(descType == (short)0x9911){
//array
boolean isNull = BinaryConverter.byteArrayToShort (rawBytes, colDescs + 2) == (short)0Xffff ? true : false; //is whole array null //@nullelem
dataIsArrayFromHost_[i] = 1; //@nullelem array type
if(isNull){
colDescs += 4; //null = x9911 xffff skip 4 to next description
indicatorOffsetsFromHost_[i] = (i == 0 ? 0 : indicatorOffsetsFromHost_[i-1] + (indicatorCountsFromHost_[i-1] * indicatorSize_));
indicatorCountsFromHost_[i] = 0; //flag that array is null or zero length array if 0 indicator counts and type of array
dataOffsetsFromHost_[i] = (i == 0 ? 0 : dataOffsetsFromHost_[i-1]); //keep same as prev since null arrays have no data (so we can later keep a running total)(ie no -1 values)
totalDataLengthsFromHost_[i] = 0;
arrayDataLengthsFromHost_[i] = 0; /*@G2A*/
dataIsNullArrayFromHost_[i] = -1; //@nullelem null array
}else{
int dataLen = BinaryConverter.byteArrayToInt (rawBytes, colDescs + 4);
int arrayLen = BinaryConverter.byteArrayToInt(rawBytes, colDescs + 8); //element count //@array2
dataLenAll += (dataLen * arrayLen);
indicatorLenAll += (indicatorSize_ * arrayLen);
indicatorOffsetsFromHost_[i] = (i == 0 ? 0 : indicatorOffsetsFromHost_[i-1] + (indicatorCountsFromHost_[i-1] * indicatorSize_));
indicatorCountsFromHost_[i] = arrayLen;
dataOffsetsFromHost_[i] = (i == 0 ? 0 : dataOffsetsFromHost_[i-1] + totalDataLengthsFromHost_[i-1]); //keep same as prev since null arrays have no data (so we can later keep a running total)(ie no -1 values)
totalDataLengthsFromHost_[i] = arrayLen * dataLen;
arrayDataLengthsFromHost_[i] = dataLen; /*@G2A*/
colDescs += 12; //0x9911=2, datatype=2, datalen=4, arraylen=4 -> 12 //@array2
dataIsNullArrayFromHost_[i] = 0; //@nullelem null array
}
}else if(descType == (short)0x9912){
//non-array
dataIsArrayFromHost_[i] = 0; //@nullelem non-array type
int dataLen = BinaryConverter.byteArrayToInt (rawBytes, colDescs + 4);
dataLenAll += dataLen;
indicatorLenAll += indicatorSize_;
indicatorOffsetsFromHost_[i] = (i == 0 ? 0 : indicatorOffsetsFromHost_[i-1] + (indicatorCountsFromHost_[i-1] * indicatorSize_));
indicatorCountsFromHost_[i] = 1;
dataOffsetsFromHost_[i] = (i == 0 ? 0 : dataOffsetsFromHost_[i-1] + totalDataLengthsFromHost_[i-1]); //keep same as prev since null arrays have no data (so we can later keep a running total)(ie no -1 values)
totalDataLengthsFromHost_[i] = dataLen;
arrayDataLengthsFromHost_[i] = 0; /*@G2A*/
colDescs += 8; //0x9911=2, datatype=2, datalen=4 -> 8
}
}
//headerLength is len of all non-relevant datastream data and count and 9911s and 9912s (not array header portion only!)
headerLength = colDescs - offset_ ; //above, colDescs did not start at 0, just decrement offset
//Here, lengthFromHost_ is length of all the indicators and data
lengthFromHost_ = headerLength + indicatorLenAll + dataLenAll; //total size of x382f/x3901
rawBytes_ = rawBytes;
headerOffsetFromHost_ = offset_;
indicatorOffsetFromHost_ = offset_ + headerLength;
dataOffsetFromHost_ = indicatorOffsetFromHost_ + indicatorLenAll; //@array start of data in rawBytes[]
//Note: end of stream offset= offset_ + lengthFromHost_
}
else {
//input array
//This part is when sending input parms x382f
rawBytes_ = rawBytes;
//offset_ is start of header block (including non array info not used)
offset_ = offset; //index into rawBytes_[] (toHost)
headerCurOffsetToHost_ = offset_ + actual382fInArrayStart_; //initialize to 4 for consistency token
setColumnCount (columnCount_);
indicatorCurOffsetToHost_ = offset_ + actual382fInArrayStart_ + headerTotalSizeToHost_; //index into rawBytes_[] (toHost)
dataCurOffsetToHost_ = indicatorCurOffsetToHost_ + indicatorTotalSizeToHost_; //index into rawBytes_[] (toHost)
}
}
public int getLength ()
{
if(dataTotalSizeToHost_ == -1)
return lengthFromHost_; //total stream length
else
return actual382fInArrayStart_ + headerTotalSizeToHost_ + indicatorTotalSizeToHost_ + dataTotalSizeToHost_;
}
public int getConsistencyToken ()
{
//from output stream
return BinaryConverter.byteArrayToInt (rawBytes_, offset_);
}
public int getRowCount ()
{
return rowCount_;
}
public int getColumnCount ()
{
return columnCount_;
}
public int getIndicatorSize ()
{
return indicatorSize_;
}
public int getRowSize ()
{
//@array no-op
return -1;
}
public int getIndicator (int rowIndex, int columnIndex)
{
return getIndicator(rowIndex, columnIndex, -1); //@nullelem -1 is for getting indicator of array (not element) or non-array data type
}
public int getRowDataOffset (int rowIndex)
{
//return offset to start of row. In our case we only have 1 row, so we can ignore rowIndex. (for now at least)
//@array
if(dataCurOffsetToHost_ == -1)
return dataOffsetFromHost_;
else
return dataCurOffsetToHost_; //Note that this index may increment with each write to the byte array. (but currently does not)
}
public byte[] getRawBytes ()
{
//@array
return rawBytes_;
}
public void setConsistencyToken (int consistencyToken)
{
//same for both input and output
BinaryConverter.intToByteArray (consistencyToken, rawBytes_,
offset_); //@array
}
public void setRowCount (int rowCount)
{
//@array no-op
}
public void setColumnCount (int columnCount)
{
//input parm offset only
BinaryConverter.shortToByteArray ((short) columnCount, rawBytes_,
headerCurOffsetToHost_); //@array
headerCurOffsetToHost_ += 2; //increment to location of first 9911/9912
}
public void setIndicatorSize (int indicatorSize)
{
//@array no-op
}
public void setRowSize (int rowSize)
{
//@array no-op
}
/**
*
* @param columnIndex
* @param type type of column
* @param indicatorValue
* @param elementDataType if type is array, then type of elements in array
* @param dataTypeSize size of data (if array, then array length * element datatype size)
* @param arrayLength
*/
public void setHeaderColumnInfo (int columnIndex, short type, short indicatorValue, short elementDataType, int dataTypeSize, short arrayLength)
{
//3 possibilities:
//1 Array = �9911'x , data type 2 bytes, data length 4 bytes, # of data items 4 bytes
//2 Null Array = �9911'x , FFFF (9911 + indicator)
//3 NonArray = �9912'x , data type 2 bytes, data length 4 bytes
if(type == SQLData.NATIVE_ARRAY)
{
if(indicatorValue == 0)
{
//1
BinaryConverter.shortToByteArray ((short) 0x9911,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
//set datatype of element
BinaryConverter.shortToByteArray (elementDataType,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
//set element data size
BinaryConverter.intToByteArray (dataTypeSize,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 4; //increment 2 bytes
//set array length
BinaryConverter.intToByteArray (arrayLength,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 4; //increment 4 bytes //@array2
}
else
{
//2
BinaryConverter.shortToByteArray ((short) 0x9911,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
//set indicator value of array (not elements)
BinaryConverter.shortToByteArray ((short) indicatorValue,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
}
}
else
{
//3 non array type
BinaryConverter.shortToByteArray ((short) 0x9912,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
//set datatype of column
BinaryConverter.shortToByteArray (type,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 2; //increment 2 bytes
//set length of data
BinaryConverter.intToByteArray (dataTypeSize,
rawBytes_, headerCurOffsetToHost_);
headerCurOffsetToHost_ += 4; //increment 2 bytes
}
}
public void setIndicator (int rowIndex, int columnIndex, int indicator)
{
//Call this iteratively for each element in the array. (for both null and non-null so that indicatorCurOffsetToHost_ will increment properly)
//We do not know anything about where to set the indicator for a given column since array lengths vary
//A rowIndex of -1 tells us that the array is null. (need to update inside of header region id flow
//0x9911FFFF to 0x382F datastream)
if(rowIndex == -1)
{
//set header 9911ffff
//If array is null we set the indicator in the header part of the stream.
//This means that we must also set the header part at the same time. So call setHeaderColumnInfo()
setHeaderColumnInfo(columnIndex, (short)SQLData.NATIVE_ARRAY, (short)-1, (short)0, 0, (short)0);
//just need to set header for null arrays
}
else
{
//this sets indicator for both array elements and for non-array single data types
BinaryConverter.shortToByteArray ((short) indicator,
rawBytes_, indicatorCurOffsetToHost_);
indicatorCurOffsetToHost_ += 2; //increment 2 bytes
}
}
/*
Specifies if variable-length fields are compressed.
@return true if variable-length fields are compressed, false otherwise.
*/
public boolean isVariableFieldsCompressed()
{
return false;
}
// Resets the number of rows to the total number of rows minus the number of rows that contain aliases.
// This method is called by AS400JDBCDatabaseMetaData.parseResultData().
public void resetRowCount(int rowCount){
//@array no-op
}
// Sets the number of aliases the result data contains.
// This method is called by AS400JDBCDatabaseMetaData.parseResultData().
public void setAliasCount(int aliases){
//@array no-op
}
//@array
//Returns indicator (-1 array index means to get indicator of array or non-array data) 0-x means indicator of that elem in the array
public int getIndicator (int rowIndex, int columnIndex, int arrayIndex){
if(arrayIndex == -1) //@nullelem
{
if( dataIsArrayFromHost_[columnIndex] == 0)
{
//non array
return BinaryConverter.byteArrayToShort (rawBytes_,
indicatorOffsetFromHost_ + indicatorOffsetsFromHost_[columnIndex] ); //first elem in indicatorOffsetsFromHost_ is for non-array data
}else
{
return dataIsNullArrayFromHost_[columnIndex]; //@nullelem already set above in this array
//is array
/* if ( indicatorCountsFromHost_[columnIndex] == 0) //@nullelem
return -1; //array type and it is null (special case) (whole array is null, no elements)
else
{
//not null
return 0;
}*/
}
}
else //get indicator of array element
{
return BinaryConverter.byteArrayToShort (rawBytes_,
indicatorOffsetFromHost_ + indicatorOffsetsFromHost_[columnIndex] + (arrayIndex * indicatorSize_)); //get indicator of array elem
}
}
//@array
//returns size footprint of data in column
/**
* Returns the size footprint of data in column.
* For arrays, this is arrayLen * arrayDataLen
*/
/*@G2A*/
public int getDataTotalSize (int colIndex){
return totalDataLengthsFromHost_[colIndex];
}
public int[] getArrayDataLengthsFromHost() {
return arrayDataLengthsFromHost_;
}
/* combatibility method */
public int[] getDataLengthsFromHost(){
return totalDataLengthsFromHost_;
}
public int[] getTotalDataLengthsFromHost(){
return totalDataLengthsFromHost_;
}
public int[] getIndicatorCountsFromHost(){
return indicatorCountsFromHost_;
}
public void logInformation(String prefix) {
JDTrace.logInformation(this, prefix+"offset_="+offset_);
JDTrace.logInformation(this, prefix+"vlfCompressed_="+vlfCompressed_);
JDTrace.logInformation(this, prefix+"rowCount_="+rowCount_);
JDTrace.logInformation(this, prefix+"columnCount_="+columnCount_);
JDTrace.logInformation(this, prefix+"indicatorSize_="+indicatorSize_);
JDTrace.logInformation(this, prefix+"headerCurOffsetToHost_="+headerCurOffsetToHost_);
JDTrace.logInformation(this, prefix+"indicatorCurOffsetToHost_="+indicatorCurOffsetToHost_);
JDTrace.logInformation(this, prefix+"dataCurOffsetToHost_="+dataCurOffsetToHost_);
JDTrace.logInformation(this, prefix+"headerTotalSizeToHost_="+headerTotalSizeToHost_);
JDTrace.logInformation(this, prefix+"indicatorTotalSizeToHost_="+indicatorTotalSizeToHost_);
JDTrace.logInformation(this, prefix+"dataTotalSizeToHost_="+dataTotalSizeToHost_);
JDTrace.logInformation(this, prefix+"headerOffsetFromHost_="+headerOffsetFromHost_);
JDTrace.logInformation(this, prefix+"indicatorOffsetFromHost_="+indicatorOffsetFromHost_);
JDTrace.logInformation(this, prefix+"dataOffsetFromHost_="+dataOffsetFromHost_);
JDTrace.logInformation(this, prefix+"lengthFromHost_="+lengthFromHost_);
}
}