in java/org.apache.derby.client/org/apache/derby/client/net/NetCursor.java [130:376]
boolean calculateColumnOffsetsForRow_(int rowIndex,
boolean allowServerFetch)
throws SqlException, DisconnectException
{
int daNullIndicator = CodePoint.NULLDATA;
int colNullIndicator = CodePoint.NULLDATA;
int length;
int[] columnDataPosition = null;
int[] columnDataComputedLength = null;
boolean[] columnDataIsNull = null;
boolean receivedDeleteHoleWarning = false;
boolean receivedRowUpdatedWarning = false;
if ((position_ == lastValidBytePosition_) &&
(netResultSet_ != null) && (netResultSet_.scrollable_)) {
return false;
}
if (hasLobs_) {
extdtaPositions_.clear(); // reset positions for this row
}
NetSqlca[] netSqlca = this.parseSQLCARD(qrydscTypdef_);
// If we don't have at least one byte in the buffer for the DA null indicator,
// then we need to send a CNTQRY request to fetch the next block of data.
// Read the DA null indicator. Do this before we close mark the statement
// closed on the server. DERBY-3230
daNullIndicator = readFdocaOneByte();
if (netSqlca != null) {
for (int i=0;i<netSqlca.length; i++) {
int sqlcode = netSqlca[i].getSqlCode();
if (sqlcode < 0) {
throw new SqlException(netAgent_.logWriter_,
netSqlca[i]);
} else {
if (sqlcode == SqlCode.END_OF_DATA.getCode()) {
setAllRowsReceivedFromServer(true);
if (netResultSet_ != null &&
netSqlca[i].containsSqlcax()) {
netResultSet_.setRowCountEvent(
netSqlca[i].getRowCount());
}
} else if (netResultSet_ != null && sqlcode > 0) {
String sqlState = netSqlca[i].getSqlState();
if (!sqlState.equals(SQLState.ROW_DELETED) &&
!sqlState.equals(SQLState.ROW_UPDATED)) {
netResultSet_.accumulateWarning(
new SqlWarning(agent_.logWriter_,
netSqlca[i]));
} else {
receivedDeleteHoleWarning
|= sqlState.equals(SQLState.ROW_DELETED);
receivedRowUpdatedWarning
|= sqlState.equals(SQLState.ROW_UPDATED);
}
}
}
}
}
setIsUpdataDeleteHole(rowIndex, receivedDeleteHoleWarning);
setIsRowUpdated(receivedRowUpdatedWarning);
// In the case for held cursors, the +100 comes back as part of the QRYDTA, and as
// we are parsing through the row that contains the SQLCA with +100, we mark the
// nextRowPosition_ which is the lastValidBytePosition_, but we don't mark the
// currentRowPosition_ until the next time next() is called causing the check
// cursor_.currentRowPositionIsEqualToNextRowPosition () to fail in getRow() and thus
// not returning 0 when it should. So we need to mark the current row position immediately
// in order for getRow() to be able to pick it up.
// markNextRowPosition() is called again once this method returns, but it is ok
// since it's only resetting nextRowPosition_ to position_ and position_ will
// not change again from this point.
if (allRowsReceivedFromServer() &&
(position_ == lastValidBytePosition_)) {
markNextRowPosition();
makeNextRowPositionCurrent();
return false;
}
// If data flows....
if (daNullIndicator == 0x0) {
if (SanityManager.DEBUG && receivedDeleteHoleWarning) {
SanityManager.THROWASSERT("Delete hole warning received: nulldata expected");
}
incrementRowsReadEvent();
// netResultSet_ is null if this method is invoked from Lob.position()
// If row has exceeded the size of the ArrayList, new up a new int[] and add it to the
// ArrayList, otherwise just reuse the int[].
if (netResultSet_ != null && netResultSet_.scrollable_) {
columnDataPosition = allocateColumnDataPositionArray(rowIndex);
columnDataComputedLength = allocateColumnDataComputedLengthArray(rowIndex);
columnDataIsNull = allocateColumnDataIsNullArray(rowIndex);
// Since we are no longer setting the int[]'s to null for a delete/update hole, we need
// another way of keeping track of the delete/update holes.
setIsUpdataDeleteHole(rowIndex, false);
} else {
// Use the arrays defined on the Cursor for forward-only cursors.
// can they ever be null
if (columnDataPosition_ == null || columnDataComputedLength_ == null || isNull_ == null) {
allocateColumnOffsetAndLengthArrays();
}
columnDataPosition = columnDataPosition_;
columnDataComputedLength = columnDataComputedLength_;
columnDataIsNull = isNull_;
}
// Loop through the columns
for (int index = 0; index < columns_; index++) {
// If column is nullable, read the 1-byte null indicator.
if (nullable_[index])
// Need to pass the column index so all previously calculated offsets can be
// readjusted if the query block splits on a column null indicator.
// null indicators from FD:OCA data
// 0 to 127: a data value will flow.
// -1 to -128: no data value will flow.
{
colNullIndicator = readFdocaOneByte(index);
}
// If non-null column data
if (!nullable_[index] || (colNullIndicator >= 0 && colNullIndicator <= 127)) {
// Set the isNull indicator to false
columnDataIsNull[index] = false;
switch (typeToUseForComputingDataLength_[index]) {
// for fixed length data
case Typdef.FIXEDLENGTH:
columnDataPosition[index] = position_;
if (isGraphic_[index]) {
columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
} else {
columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
}
break;
// for variable character string and variable byte string,
// there are 2-byte of length in front of the data
case Typdef.TWOBYTELENGTH:
columnDataPosition[index] = position_;
length = readFdocaTwoByteLength(index);
// skip length + the 2-byte length field
if (isGraphic_[index]) {
columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 2;
} else {
columnDataComputedLength[index] = skipFdocaBytes(length, index) + 2;
}
break;
// For decimal columns, determine the precision, scale, and the representation
case Typdef.DECIMALLENGTH:
columnDataPosition[index] = position_;
columnDataComputedLength[index] = skipFdocaBytes(getDecimalLength(index), index);
break;
case Typdef.LOBLENGTH:
columnDataPosition[index] = position_;
columnDataComputedLength[index] = this.skipFdocaBytes(fdocaLength_[index] & 0x7fff, index);
break;
// for short variable character string and short variable byte string,
// there is a 1-byte length in front of the data
case Typdef.ONEBYTELENGTH:
columnDataPosition[index] = position_;
length = readFdocaOneByte(index);
// skip length + the 1-byte length field
if (isGraphic_[index]) {
columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 1;
} else {
columnDataComputedLength[index] = skipFdocaBytes(length, index) + 1;
}
break;
default:
columnDataPosition[index] = position_;
if (isGraphic_[index]) {
columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
} else {
columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
}
break;
}
} else if ((colNullIndicator & 0x80) == 0x80) {
// Null data. Set the isNull indicator to true.
columnDataIsNull[index] = true;
}
}
// set column offsets for the current row.
columnDataPosition_ = columnDataPosition;
columnDataComputedLength_ = columnDataComputedLength;
isNull_ = columnDataIsNull;
if (!allRowsReceivedFromServer()) {
calculateLobColumnPositionsForRow();
// Flow another CNTQRY if we are blocking, are using rtnextrow, and expect
// non-trivial EXTDTAs for forward only cursors. Note we do not support
// EXTDTA retrieval for scrollable cursors.
// if qryrowset was sent on excsqlstt for a sp call, which is only the case
if (blocking_ && rtnextrow_ &&
!netResultSet_.scrollable_ &&
!extdtaPositions_.isEmpty()) {
if (allowServerFetch) {
netResultSet_.flowFetch();
} else {
return false;
}
}
}
} else {
if (netResultSet_ != null && netResultSet_.scrollable_) {
if (receivedDeleteHoleWarning) {
setIsUpdataDeleteHole(rowIndex, true);
} else {
if (SanityManager.DEBUG) {
// Invariant: for SUR, we introduced the warning
// in addition to null data.
SanityManager
.THROWASSERT("Delete hole warning expected");
}
}
}
}
// If blocking protocol is used, we could have already received an ENDQRYRM,
// which sets allRowsReceivedFromServer_ to true. It's safe to assume that all of
// our QRYDTA's have been successfully copied to the dataBuffer. And even though
// the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through
// the data in the dataBuffer.
// But in the case where fixed row protocol is used,
if (!blocking_ && allRowsReceivedFromServer() &&
daNullIndicator == 0xFF) {
return false;
} else {
return true;
}
}