You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by jb...@apache.org on 2005/05/02 08:26:03 UTC

svn commit: r165585 [29/42] - in /incubator/derby/code/trunk/java/client/org/apache/derby: client/ client/am/ client/net/ client/resources/ jdbc/

Modified: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java?rev=165585&r1=165584&r2=165585&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java (original)
+++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Sun May  1 23:25:59 2005
@@ -20,1047 +20,1031 @@
 
 package org.apache.derby.client.net;
 
-import org.apache.derby.client.am.SqlException;
-import org.apache.derby.client.am.SqlWarning;
-import org.apache.derby.client.am.SignedBinary;
-import org.apache.derby.client.am.DisconnectException;
+import org.apache.derby.client.am.Agent;
 import org.apache.derby.client.am.Blob;
 import org.apache.derby.client.am.Clob;
-import org.apache.derby.client.am.Agent;
+import org.apache.derby.client.am.DisconnectException;
+import org.apache.derby.client.am.SignedBinary;
+import org.apache.derby.client.am.SqlException;
+import org.apache.derby.client.am.SqlWarning;
 import org.apache.derby.client.am.Types;
 
-public class NetCursor extends org.apache.derby.client.am.Cursor
-{
+public class NetCursor extends org.apache.derby.client.am.Cursor {
+
+    NetResultSet netResultSet_;
+    NetAgent netAgent_;
+
+    Typdef qrydscTypdef_;
+
+    int targetSqlamForTypdef_;
+
+
+    // override column meta data
+    int numMddOverrides_;
+    int maximumRowSize_;
+    boolean blocking_;  // if true, multiple rows may be "blocked" in a single reply
+
+    // Raw fdoca column meta data.
+    int[] typeToUseForComputingDataLength_;
+    boolean[] isGraphic_;
+
+    // key = column position, value = index into extdtaData_
+    java.util.HashMap extdtaPositions_;
+    java.util.ArrayList extdtaData_; // queue to hold EXTDTA data that hasn't been correlated to its column #
+
+
+    boolean rtnextrow_ = true;
+
+    //-----------------------------constants--------------------------------------
+
+    //---------------------constructors/finalizer---------------------------------
+
+    NetCursor(NetAgent netAgent) {
+        super(netAgent);
+        netAgent_ = netAgent;
+        numMddOverrides_ = 0;
+        maximumRowSize_ = 0;
+        extdtaPositions_ = new java.util.HashMap();
+        extdtaData_ = new java.util.ArrayList();
+    }
+
+    NetCursor(NetAgent netAgent,
+              int qryprctyp)  //protocolType, CodePoint.FIXROWPRC | CodePoint.LMTBLKPRC
+    {
+        this(netAgent);
+        if (qryprctyp == CodePoint.FIXROWPRC) {
+            blocking_ = false;
+        } else if (qryprctyp == CodePoint.LMTBLKPRC) {
+            blocking_ = true;
+        }
+    }
+    //-----------------------------parsing the data buffer------------------------
+
+    // Pseudo-code:
+    //   parse thru the current row in dataBuffer computing column offsets
+    //   if (we hit the super.lastValidBytePosition, ie. encounter partial row) {
+    //     shift partial row bytes to beginning of dataBuffer (this.shiftPartialRowToBeginning())
+    //     reset current row position (also done by this.shiftPartialRowToBeginning())
+    //     send and recv continue-query into commBuffer (rs.flowContinueQuery())
+    //     parse commBuffer up to QRYDTA (rs.flowContinueQuery())
+    //     copy query data from reply's commBuffer to our dataBuffer (this.copyQrydta())
+    //   }
+    // Returns true if the current row position is a valid row position.
+    // rename this to parse*()
+    protected boolean calculateColumnOffsetsForRow_(int rowIndex) throws SqlException, org.apache.derby.client.am.DisconnectException {
+        int daNullIndicator = CodePoint.NULLDATA;
+        int colNullIndicator = CodePoint.NULLDATA;
+        int length;
+
+        if (hasLobs_) {
+            extdtaPositions_.clear();  // reset positions for this row
+        }
+
+        int[] columnDataPosition = null;
+        int[] columnDataComputedLength = null;
+        boolean[] columnDataIsNull = null;
+
+        if ((position_ == lastValidBytePosition_) &&
+                (netResultSet_ != null) && (netResultSet_.scrollable_)) {
+            return false;
+        }
+
+        NetSqlca netSqlca = this.parseSQLCARD(qrydscTypdef_);
+
+        if (netSqlca != null) {
+            int sqlcode = netSqlca.getSqlCode();
+            if (sqlcode < 0) {
+                throw new SqlException(netAgent_.logWriter_, netSqlca);
+            } else {
+                if (sqlcode > 0) {
+                    if (sqlcode == 100) {
+                        allRowsReceivedFromServer_ = true;
+                        if (netResultSet_ != null && netSqlca.containsSqlcax()) {
+                            netResultSet_.setRowCountEvent(netSqlca.getRowCount(qrydscTypdef_));
+                        }
+                    } else if (netResultSet_ != null) {
+                        netResultSet_.accumulateWarning(new SqlWarning(agent_.logWriter_, netSqlca));
+                    }
+                }
+            }
+        }
+
+        // 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.
+        daNullIndicator = readFdocaOneByte();
+
+        // 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) {
+
+            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_ &&
+                        extdtaPositions_.size() > 0 && !netResultSet_.scrollable_) {
+                    if (!extdtaPositions_.isEmpty()) {
+                        netResultSet_.flowFetch();
+                    }
+                }
+            }
+        }
+
+        // Else if this row is null, only add to the isRowNullCache_ if the cursor is scrollable.
+        else {
+            if (netResultSet_ != null && netResultSet_.scrollable_) {
+                setIsUpdataDeleteHole(rowIndex, true);
+            }
+        }
+
+        // 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;
+        }
+    }
+
+    protected boolean isDataBufferNull() {
+        if (dataBuffer_ == null) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected void allocateDataBuffer() {
+        int length;
+        if (maximumRowSize_ > DssConstants.MAX_DSS_LEN) {
+            length = maximumRowSize_;
+        } else {
+            length = DssConstants.MAX_DSS_LEN;
+        }
+
+        dataBuffer_ = new byte[length];
+        position_ = 0;
+        lastValidBytePosition_ = 0;
+    }
+
+    protected void allocateDataBuffer(int length) {
+        dataBuffer_ = new byte[length];
+    }
+
+
+    private int readFdocaInt() throws org.apache.derby.client.am.DisconnectException, SqlException {
+        if ((position_ + 4) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        int i = SignedBinary.getInt(dataBuffer_, position_);
+        position_ += 4;
+        return i;
+    }
+
+    // Reads 1-byte from the dataBuffer from the current position.
+    // If position is already at the end of the buffer, send CNTQRY to get more data.
+    private int readFdocaOneByte() throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if (position_ == lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+        return dataBuffer_[position_++] & 0xff;
+    }
+
+    // Reads 1-byte from the dataBuffer from the current position.
+    // If position is already at the end of the buffer, send CNTQRY to get more data.
+    private int readFdocaOneByte(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if (position_ == lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow(index);
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+        return dataBuffer_[position_++] & 0xff;
+    }
+
+    // Reads <i>length</i> number of bytes from the dataBuffer starting from the
+    // current position.  Returns a new byte array which contains the bytes read.
+    // If current position plus length goes past the lastValidBytePosition, send
+    // CNTQRY to get more data.
+    private byte[] readFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        byte[] b = new byte[length];
+        ;
+
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + length) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        for (int i = 0; i < length; i++) {
+            b[i] = dataBuffer_[position_++];
+        }
+
+        return b;
+    }
+
+    // Reads 2-bytes from the dataBuffer starting from the current position, and
+    // returns an integer constructed from the 2-bytes.  If current position plus
+    // 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data.
+    private int readFdocaTwoByteLength() throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + 2) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        return
+                ((dataBuffer_[position_++] & 0xff) << 8) +
+                ((dataBuffer_[position_++] & 0xff) << 0);
+    }
+
+    private int readFdocaTwoByteLength(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + 2) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow(index);
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        return
+                ((dataBuffer_[position_++] & 0xff) << 8) +
+                ((dataBuffer_[position_++] & 0xff) << 0);
+    }
+
+    // Check if position plus length goes past the lastValidBytePosition.
+    // If so, send CNTQRY to get more data.
+    // length - number of bytes to skip
+    // returns the number of bytes skipped
+    private int skipFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + length) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+        position_ += length;
+        return length;
+    }
+
+    private int skipFdocaBytes(int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + length) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow(index);
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        position_ += length;
+        return length;
+    }
+
+    // Shift partial row bytes to beginning of dataBuffer,
+    // and resets current row position, and lastValidBytePosition.
+    // When we shift partial row, we'll have to recalculate column offsets
+    // up to this column.
+    private void shiftPartialRowToBeginning() {
+        // Get the length to shift from the beginning of the partial row.
+        int length = lastValidBytePosition_ - currentRowPosition_;
+
+        // shift the data in the dataBufferStream
+        dataBufferStream_.reset();
+        if (dataBuffer_ != null) {
+            dataBufferStream_.write(dataBuffer_, currentRowPosition_, length);
+        }
+
+        for (int i = 0; i < length; i++) {
+            dataBuffer_[i] = dataBuffer_[currentRowPosition_ + i];
+        }
+
+        position_ = length - (lastValidBytePosition_ - position_);
+        lastValidBytePosition_ = length;
+    }
+
+    private void adjustColumnOffsetsForColumnsPreviouslyCalculated(int index) {
+        for (int j = 0; j <= index; j++) {
+            columnDataPosition_[j] -= currentRowPosition_;
+        }
+    }
+
+    private void resetCurrentRowPosition() {
+        currentRowPosition_ = 0;
+    }
+
+    // Calculates the column index for Lob objects constructed from EXTDTA data.
+    // Describe information isn't sufficient because we have to check
+    // for trivial values (nulls or zero-length) and exclude them.
+    void calculateLobColumnPositionsForRow() {
+        int currentPosition = 0;
+
+        for (int i = 0; i < columns_; i++) {
+            if (isNonTrivialDataLob(i))
+            // key = column position, data = index to corresponding data in extdtaData_
+            // ASSERT: the server always returns the EXTDTA objects in ascending order
+            {
+                extdtaPositions_.put(new Integer(i + 1), new Integer(currentPosition++));
+            }
+        }
+    }
 
-  NetResultSet netResultSet_;
-  NetAgent netAgent_;
+    // prereq: the base data for the cursor has been processed for offsets and lengths
+    boolean isNonTrivialDataLob(int index) {
+        long length = 0L;
+
+        if (isNull_[index] ||
+                (jdbcTypes_[index] != Types.BLOB &&
+                jdbcTypes_[index] != Types.CLOB)) {
+            return false;
+        }
 
-  Typdef qrydscTypdef_;
+        int position = columnDataPosition_[index];
 
-  int targetSqlamForTypdef_;
-
-
-  // override column meta data
-  int numMddOverrides_;
-  int maximumRowSize_;
-  boolean blocking_;  // if true, multiple rows may be "blocked" in a single reply
-
-  // Raw fdoca column meta data.
-  int[] typeToUseForComputingDataLength_;
-  boolean[] isGraphic_;
-
-  // key = column position, value = index into extdtaData_
-  java.util.HashMap extdtaPositions_; 
-  java.util.ArrayList extdtaData_; // queue to hold EXTDTA data that hasn't been correlated to its column #
-
-
-  boolean rtnextrow_ = true;
-
-  //-----------------------------constants--------------------------------------
-
-  //---------------------constructors/finalizer---------------------------------
-
-  NetCursor (NetAgent netAgent)
-  {
-    super (netAgent);
-    netAgent_ = netAgent;
-    numMddOverrides_ = 0;
-    maximumRowSize_ = 0;
-    extdtaPositions_ = new java.util.HashMap();
-    extdtaData_ = new java.util.ArrayList ();
-  }
-
-  NetCursor (NetAgent netAgent,
-            int qryprctyp)  //protocolType, CodePoint.FIXROWPRC | CodePoint.LMTBLKPRC
-  {
-    this (netAgent);
-    if (qryprctyp == CodePoint.FIXROWPRC)
-      blocking_ = false;
-    else if (qryprctyp == CodePoint.LMTBLKPRC)
-      blocking_ = true;
-  }
-  //-----------------------------parsing the data buffer------------------------
-
-  // Pseudo-code:
-  //   parse thru the current row in dataBuffer computing column offsets
-  //   if (we hit the super.lastValidBytePosition, ie. encounter partial row) {
-  //     shift partial row bytes to beginning of dataBuffer (this.shiftPartialRowToBeginning())
-  //     reset current row position (also done by this.shiftPartialRowToBeginning())
-  //     send and recv continue-query into commBuffer (rs.flowContinueQuery())
-  //     parse commBuffer up to QRYDTA (rs.flowContinueQuery())
-  //     copy query data from reply's commBuffer to our dataBuffer (this.copyQrydta())
-  //   }
-  // Returns true if the current row position is a valid row position.
-  // rename this to parse*() 
-  protected boolean calculateColumnOffsetsForRow_ (int rowIndex) throws SqlException, org.apache.derby.client.am.DisconnectException
-  {
-    int daNullIndicator = CodePoint.NULLDATA;
-    int colNullIndicator = CodePoint.NULLDATA;
-    int length;
-
-    if (hasLobs_)
-    extdtaPositions_.clear();  // reset positions for this row
-
-    int[] columnDataPosition = null;
-    int[] columnDataComputedLength = null;
-    boolean[] columnDataIsNull = null;
-
-    if ((position_ == lastValidBytePosition_) &&
-      (netResultSet_ != null) && (netResultSet_.scrollable_))
-       return false;
-
-    NetSqlca netSqlca = this.parseSQLCARD (qrydscTypdef_);
-
-    if (netSqlca != null) {
-      int sqlcode = netSqlca.getSqlCode();
-     if (sqlcode < 0) {
-       throw new SqlException (netAgent_.logWriter_, netSqlca);
-     }
-     else {
-       if (sqlcode > 0) {
-         if (sqlcode == 100) {
-           allRowsReceivedFromServer_ = true;
-           if (netResultSet_ != null && netSqlca.containsSqlcax())
-             netResultSet_.setRowCountEvent (netSqlca.getRowCount(qrydscTypdef_));
-         }
-         else if (netResultSet_ != null)
-           netResultSet_.accumulateWarning (new SqlWarning (agent_.logWriter_, netSqlca));
-        }
-      }
-    }
-
-    // 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.
-    daNullIndicator = readFdocaOneByte ();
-
-    // 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) {
-
-      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_ &&
-            extdtaPositions_.size () > 0 && !netResultSet_.scrollable_)
-          if (!extdtaPositions_.isEmpty())
-            netResultSet_.flowFetch ();
-      }
-    }
-
-    // Else if this row is null, only add to the isRowNullCache_ if the cursor is scrollable.
-    else {
-      if (netResultSet_ != null && netResultSet_.scrollable_) setIsUpdataDeleteHole (rowIndex, true);
-    }
-
-    // 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; 
-  }
-
-  protected boolean isDataBufferNull ()
-  {
-    if (dataBuffer_ == null)
-      return true;
-    else
-      return false;
-  }
-
-  protected void allocateDataBuffer ()
-  {
-    int length;
-    if (maximumRowSize_ > DssConstants.MAX_DSS_LEN)
-      length = maximumRowSize_;
-    else
-      length = DssConstants.MAX_DSS_LEN;
-
-    dataBuffer_ = new byte[length];
-    position_ = 0;
-    lastValidBytePosition_ = 0;
-  }
-
-  protected void allocateDataBuffer (int length)
-  {
-    dataBuffer_ = new byte[length];
-  }
-
-
-  private int readFdocaInt () throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    if ((position_ + 4) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    int i = SignedBinary.getInt (dataBuffer_, position_);
-    position_ += 4;
-    return i;
-  }
-
-  // Reads 1-byte from the dataBuffer from the current position.
-  // If position is already at the end of the buffer, send CNTQRY to get more data.
-  private int readFdocaOneByte () throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if (position_ == lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-    return dataBuffer_[position_++] & 0xff;
-  }
-
-  // Reads 1-byte from the dataBuffer from the current position.
-  // If position is already at the end of the buffer, send CNTQRY to get more data.
-  private int readFdocaOneByte (int index) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if (position_ == lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow (index);
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-    return dataBuffer_[position_++] & 0xff;
-  }
-
-  // Reads <i>length</i> number of bytes from the dataBuffer starting from the
-  // current position.  Returns a new byte array which contains the bytes read.
-  // If current position plus length goes past the lastValidBytePosition, send
-  // CNTQRY to get more data.
-  private byte[] readFdocaBytes (int length) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    byte[] b = new byte[length];;
-
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + length) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    for (int i = 0; i < length; i++)
-      b[i] = dataBuffer_[position_++];
-
-    return b;
-  }
-
-  // Reads 2-bytes from the dataBuffer starting from the current position, and
-  // returns an integer constructed from the 2-bytes.  If current position plus
-  // 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data.
-  private int readFdocaTwoByteLength () throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + 2) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    return
-      ((dataBuffer_[position_++] & 0xff) << 8) +
-      ((dataBuffer_[position_++] & 0xff) << 0);
-  }
-
-  private int readFdocaTwoByteLength (int index) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + 2) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow (index);
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    return
-      ((dataBuffer_[position_++] & 0xff) << 8) +
-      ((dataBuffer_[position_++] & 0xff) << 0);
-  }
-
-  // Check if position plus length goes past the lastValidBytePosition.
-  // If so, send CNTQRY to get more data.
-  // length - number of bytes to skip
-  // returns the number of bytes skipped
-  private int skipFdocaBytes (int length) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + length) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-    position_ += length;
-    return length;
-  }
-
-  private int skipFdocaBytes (int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + length) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow (index);
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    position_ += length;
-    return length;
-  }
-
-  // Shift partial row bytes to beginning of dataBuffer,
-  // and resets current row position, and lastValidBytePosition.
-  // When we shift partial row, we'll have to recalculate column offsets
-  // up to this column.
-  private void shiftPartialRowToBeginning ()
-  {
-    // Get the length to shift from the beginning of the partial row.
-    int length = lastValidBytePosition_ - currentRowPosition_;
-
-    // shift the data in the dataBufferStream
-    dataBufferStream_.reset ();
-    if (dataBuffer_ != null)
-      dataBufferStream_.write (dataBuffer_, currentRowPosition_, length);
-
-    for (int i = 0; i < length; i++)
-      dataBuffer_[i] = dataBuffer_[currentRowPosition_+i];
-
-    position_ = length - (lastValidBytePosition_ - position_);
-    lastValidBytePosition_ = length;
-  }
-
-  private void adjustColumnOffsetsForColumnsPreviouslyCalculated (int index)
-  {
-    for (int j = 0; j <= index; j++) {
-      columnDataPosition_[j] -= currentRowPosition_;
-    }
-  }
-
-  private void resetCurrentRowPosition ()
-  {
-    currentRowPosition_ = 0;
-  }
-
-  // Calculates the column index for Lob objects constructed from EXTDTA data.
-  // Describe information isn't sufficient because we have to check
-  // for trivial values (nulls or zero-length) and exclude them.
-  void calculateLobColumnPositionsForRow ()
-  {
-    int currentPosition = 0;
-
-    for (int i = 0; i < columns_; i++) {
-      if ( isNonTrivialDataLob (i) )
-        // key = column position, data = index to corresponding data in extdtaData_
-        // ASSERT: the server always returns the EXTDTA objects in ascending order
-        extdtaPositions_.put(new Integer(i + 1), new Integer (currentPosition++));
-    }
-  }
-
-  // prereq: the base data for the cursor has been processed for offsets and lengths
-  boolean isNonTrivialDataLob (int index)
-  {
-    long length = 0L;
-
-    if (isNull_[index] ||
-        (jdbcTypes_[index] != Types.BLOB &&
-         jdbcTypes_[index] != Types.CLOB) )
-      return false;
-
-    int position = columnDataPosition_[index];
-
-    // if the high-order bit is set, length is unknown -> set value to x'FF..FF'
-    if (((dataBuffer_[position])&0x80) == 0x80)
-      length = -1;
-    else {
-
-      byte[] lengthBytes = new byte[columnDataComputedLength_[index]];
-      byte[] longBytes = new byte[8];
-
-      System.arraycopy (dataBuffer_,
-                        position,
-                        lengthBytes,
-                        0,
-                        columnDataComputedLength_[index] );
-
-      // right-justify for BIG ENDIAN
-      int j = 0;
-      for (int i = 8 - columnDataComputedLength_[index]; i < 8; i++) {
-        longBytes[i] = lengthBytes[j];
-        j++;
-      }
-      length = SignedBinary.getLong (longBytes, 0);
-    }
-    return (length != 0L)?true:false;
-  }
-
-  protected void clearLobData_()
-  {
-    extdtaData_.clear ();
-    extdtaPositions_.clear ();
-  }
-
-  // SQLCARD : FDOCA EARLY ROW
-  // SQL Communications Area Row Description
-  //
-  // FORMAT FOR ALL SQLAM LEVELS
-  //   SQLCAGRP; GROUP LID 0x54; ELEMENT TAKEN 0(all); REP FACTOR 1
-  NetSqlca parseSQLCARD (Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    return parseSQLCAGRP (typdef);  
-  }
-
-  // SQLCAGRP : FDOCA EARLY GROUP
-  // SQL Communcations Area Group Description
-  //
-  // FORMAT FOR SQLAM <= 6
-  //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
-  //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
-  //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
-  //
-  // FORMAT FOR SQLAM >= 7
-  //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
-  //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
-  //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
-  //   SQLDIAGGRP; PROTOCOL TYPE N-GDA; ENVLID 0x56; Length Override 0
-  private NetSqlca parseSQLCAGRP (Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException
-  {
-    if (readFdocaOneByte() == CodePoint.NULLDATA)
-      return null;
-    int sqlcode = readFdocaInt();
-    byte[] sqlstate = readFdocaBytes (5);
-    byte[] sqlerrproc = readFdocaBytes (8);
-    NetSqlca netSqlca = new NetSqlca (netAgent_.netConnection_, sqlcode, sqlstate, sqlerrproc, typdef.getCcsidSbc());
-
-    parseSQLCAXGRP (typdef, netSqlca);
-
-	parseSQLDIAGGRP ();
-
-    return netSqlca;
-  }
-
-  // SQLCAXGRP : EARLY FDOCA GROUP
-  // SQL Communications Area Exceptions Group Description
-  //
-  // FORMAT FOR SQLAM <= 6
-  //   SQLRDBNME; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 18
-  //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
-  //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
-  //
-  // FORMAT FOR SQLAM >= 7
-  //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-  //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-  //   SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
-  //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
-  //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
-  private void parseSQLCAXGRP (Typdef typdef, NetSqlca netSqlca) throws DisconnectException, SqlException
-  {
-    if (readFdocaOneByte() == CodePoint.NULLDATA) {
-      netSqlca.setContainsSqlcax (false);
-      return;
-    }
-
-
-    //   SQLERRD1 to SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
-    int[] sqlerrd = new int[6];
-    for (int i = 0; i < sqlerrd.length; i++)
-      sqlerrd[i] = readFdocaInt ();
-
-    //   SQLWARN0 to SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
-    byte[] sqlwarn = readFdocaBytes (11);
-
-	// skip over the rdbnam for now
-	// SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
-	parseVCS (typdef);
+        // if the high-order bit is set, length is unknown -> set value to x'FF..FF'
+        if (((dataBuffer_[position]) & 0x80) == 0x80) {
+            length = -1;
+        } else {
+
+            byte[] lengthBytes = new byte[columnDataComputedLength_[index]];
+            byte[] longBytes = new byte[8];
+
+            System.arraycopy(dataBuffer_,
+                    position,
+                    lengthBytes,
+                    0,
+                    columnDataComputedLength_[index]);
+
+            // right-justify for BIG ENDIAN
+            int j = 0;
+            for (int i = 8 - columnDataComputedLength_[index]; i < 8; i++) {
+                longBytes[i] = lengthBytes[j];
+                j++;
+            }
+            length = SignedBinary.getLong(longBytes, 0);
+        }
+        return (length != 0L) ? true : false;
+    }
 
+    protected void clearLobData_() {
+        extdtaData_.clear();
+        extdtaPositions_.clear();
+    }
+
+    // SQLCARD : FDOCA EARLY ROW
+    // SQL Communications Area Row Description
+    //
+    // FORMAT FOR ALL SQLAM LEVELS
+    //   SQLCAGRP; GROUP LID 0x54; ELEMENT TAKEN 0(all); REP FACTOR 1
+    NetSqlca parseSQLCARD(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        return parseSQLCAGRP(typdef);
+    }
+
+    // SQLCAGRP : FDOCA EARLY GROUP
+    // SQL Communcations Area Group Description
+    //
+    // FORMAT FOR SQLAM <= 6
+    //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
+    //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
+    //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
+    //
+    // FORMAT FOR SQLAM >= 7
+    //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
+    //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
+    //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
+    //   SQLDIAGGRP; PROTOCOL TYPE N-GDA; ENVLID 0x56; Length Override 0
+    private NetSqlca parseSQLCAGRP(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
+        if (readFdocaOneByte() == CodePoint.NULLDATA) {
+            return null;
+        }
+        int sqlcode = readFdocaInt();
+        byte[] sqlstate = readFdocaBytes(5);
+        byte[] sqlerrproc = readFdocaBytes(8);
+        NetSqlca netSqlca = new NetSqlca(netAgent_.netConnection_, sqlcode, sqlstate, sqlerrproc, typdef.getCcsidSbc());
+
+        parseSQLCAXGRP(typdef, netSqlca);
+
+        parseSQLDIAGGRP();
+
+        return netSqlca;
+    }
+
+    // SQLCAXGRP : EARLY FDOCA GROUP
+    // SQL Communications Area Exceptions Group Description
+    //
+    // FORMAT FOR SQLAM <= 6
+    //   SQLRDBNME; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 18
+    //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
+    //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
+    //
+    // FORMAT FOR SQLAM >= 7
+    //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+    //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+    //   SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
     //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
     //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
-    int varcharLength = readFdocaTwoByteLength();  // mixed length
-    byte[] sqlerrmc = null;
-    int sqlerrmcCcsid = 0;
-    if (varcharLength != 0) {                    // if mixed
-      sqlerrmc = readFdocaBytes(varcharLength);      // read mixed bytes
-      sqlerrmcCcsid = typdef.getCcsidMbc();
-      skipFdocaBytes(2);                          // skip single length
-    }
-    else {
-      varcharLength = readFdocaTwoByteLength();  // read single length
-      sqlerrmc = readFdocaBytes (varcharLength);     // read single bytes
-      sqlerrmcCcsid = typdef.getCcsidSbc();
-    }
-
-    netSqlca.setSqlerrd (sqlerrd);
-    netSqlca.setSqlwarnBytes (sqlwarn);
-    netSqlca.setSqlerrmcBytes (sqlerrmc, sqlerrmcCcsid);
-  }
-
-  // SQLDIAGGRP : FDOCA EARLY GROUP
-  private void parseSQLDIAGGRP () throws DisconnectException, SqlException
-  {
-    if (readFdocaOneByte() == CodePoint.NULLDATA)
-      return;
-
-    netAgent_.accumulateChainBreakingReadExceptionAndThrow (new DisconnectException (
-      netAgent_,
-      "parseSQLDIAGGRP not yet implemented"));
-  }
-
-  private String parseVCS (Typdef typdefInEffect) throws DisconnectException, SqlException
-  {
-    return readFdocaString(readFdocaTwoByteLength(),
-                           typdefInEffect.getCcsidSbcEncoding());
-  }
-
-  // This is not used for column data.
-  private String readFdocaString (int length, String encoding) throws DisconnectException, SqlException
-  {
-    if (length == 0)
-      return null;
-
-    // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-    // so there is no need to drive a flowFetch (continue query) request for singleton select.
-    if ((position_ + length) > lastValidBytePosition_) {
-      // Check for ENDQRYRM, throw SqlException if already received one.
-      checkAndThrowReceivedEndqryrm ();
-
-      // Send CNTQRY to complete the row/rowset.
-      int lastValidByteBeforeFetch = completeSplitRow ();
-
-      // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-      // throw a SqlException for the ENDQRYRM.
-      checkAndThrowReceivedEndqryrm (lastValidByteBeforeFetch);
-    }
-
-    String s = null;
-
-    try {
-      s = new String (dataBuffer_, position_, length, encoding);
-    }
-    catch (java.io.UnsupportedEncodingException e) {
-      netAgent_.accumulateChainBreakingReadExceptionAndThrow (
-        new org.apache.derby.client.am.DisconnectException (
-          e,
-          netAgent_,
-          "encoding not supported!!"));
-    }
-
-    position_ += length;
-    return s;
-  }
-
-  void allocateColumnOffsetAndLengthArrays ()
-  {
-    columnDataPosition_ = new int[columns_];
-    columnDataComputedLength_ = new int[columns_];
-    isNull_ = new boolean[columns_];
-  }
-
-  void setBlocking (int queryProtocolType)
-  {
-    if (queryProtocolType == CodePoint.LMTBLKPRC) 
-      blocking_ = true;
-    else
-      blocking_ = false;
-  }
-
-  protected byte[] findExtdtaData (int column)
-  {
-    byte[] data = null;
-
-    // locate the EXTDTA bytes, if any
-    Integer key = new Integer(column);
-
-    if (extdtaPositions_.containsKey (key)) {
-      //  found, get the data
-      int extdtaQueuePosition = ((Integer) extdtaPositions_.get(key)).intValue();
-      data = (byte[]) (extdtaData_.get(extdtaQueuePosition));
-    }
-
-    return data;
-  }
-
-  public Blob getBlobColumn_ (int column, Agent agent) throws SqlException
-  {
-    int index = column - 1;
-    int dataOffset;
-    byte[] data;
-    Blob blob = null;
-
-    // locate the EXTDTA bytes, if any
-    data = findExtdtaData (column);
-
-    if (data != null) {
-      // data found
-      // set data offset based on the presence of a null indicator 
-		if (!nullable_[index])
-			dataOffset = 0;
-		else
-			dataOffset = 1;
-
-      blob = new Blob ( data, agent, dataOffset);
-    }
-    else {
-      blob = new Blob (new byte[0], agent, 0);
-    }
-
-    return blob;
-  }
-
-
-  public Clob getClobColumn_ (int column, Agent agent) throws SqlException
-  {
-    int index = column - 1;
-    int dataOffset;
-    byte[] data;
-    Clob clob = null;
-
-    // locate the EXTDTA bytes, if any
-    data = findExtdtaData (column);
-
-    if (data != null) {
-      // data found
-      // set data offset based on the presence of a null indicator
-      if (! nullable_[index])
-        dataOffset = 0;
-      else
-        dataOffset = 1;
-      clob = new Clob (agent, data, charsetName_[index], dataOffset);
-    }
-    else {
-      // the locator is not valid, it is a zero-length LOB
-      clob = new Clob (agent, "");
-    }
-
-    return clob;
-  }
-
-  public byte[] getClobBytes_ (int column, int[] dataOffset /*output*/) throws SqlException
-  {
-    int index = column - 1;
-    byte[] data = null;
-
-    // locate the EXTDTA bytes, if any
-    data = findExtdtaData (column);
-
-    if (data != null) {
-      // data found
-      // set data offset based on the presence of a null indicator 
-      if (! nullable_[index])
-       dataOffset[0] = 0;
-      else
-       dataOffset[0] = 1;
-    }
-
-    return data;
-  }
-
-  // this is really an event-callback from NetStatementReply.parseSQLDTARDarray()
-  void initializeColumnInfoArrays (Typdef typdef,
-                           int columnCount, int targetSqlamForTypdef) throws DisconnectException
-  {
-    qrydscTypdef_ = typdef;
-
-    // Allocate  arrays to hold the descriptor information.
-    setNumberOfColumns (columnCount);
-    fdocaLength_ = new int[columnCount];
-    isGraphic_ = new boolean[columnCount];
-    typeToUseForComputingDataLength_ = new int[columnCount];
-    targetSqlamForTypdef_ = targetSqlamForTypdef;
-  }
-
-
-  int ensureSpaceForDataBuffer (int ddmLength) 
-  {
-    if (dataBuffer_ == null) {
-      allocateDataBuffer();
-    }
-    //super.resultSet.cursor.clearColumnDataOffsetsCache();
-    // Need to know how many bytes to ask from the Reply object,
-    // and handle the case where buffer is not big enough for all the bytes.
-    // Get the length in front of the code point first.
-
-    int bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
-
-    // Make sure the buffer has at least ddmLength amount of room left.
-    // If not, expand the buffer before calling the getQrydtaData() method.
-    if (bytesAvailableInDataBuffer < ddmLength) {
-
-      // Get a new buffer that is twice the size of the current buffer.
-      // Copy the contents from the old buffer to the new buffer.
-      int newBufferSize = 2 * dataBuffer_.length;
-
-      while (newBufferSize < ddmLength) {
-        newBufferSize = 2 * newBufferSize;
-      }
-
-      byte[] tempBuffer = new byte[newBufferSize];
-
-      System.arraycopy (dataBuffer_,
-                        0,
-                        tempBuffer,
-                        0,
-                        lastValidBytePosition_);
-
-      // Make the new buffer the dataBuffer.
-      dataBuffer_ = tempBuffer;
-
-      // Recalculate bytesAvailableInDataBuffer
-      bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
-    }
-    return bytesAvailableInDataBuffer;
-  }
-
-  protected void getMoreData_ () throws SqlException
-  {
-    // reset the dataBuffer_ before getting more data if cursor is foward-only.
-    // getMoreData() is only called in Cursor.next() when current position is
-    // equal to lastValidBytePosition_.
-    if (netResultSet_.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY)
-      resetDataBuffer();
-    netResultSet_.flowFetch ();
-  }
-
-  public void nullDataForGC ()       // memory leak fix 
-  {
-    super.nullDataForGC();
-    qrydscTypdef_ = null;
-    typeToUseForComputingDataLength_ = null;
-    isGraphic_ = null;
-
-    if (extdtaPositions_ != null) extdtaPositions_.clear();
-    extdtaPositions_ = null;
-
-    if (extdtaData_ != null) extdtaData_.clear();
-    extdtaData_ = null;
-  }
-
-  // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD.
-  // This means some error has occurred on the server and the server is terminating the query.
-  // Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already
-  // been received.  If so, do not send CNTQRY because the cursor is already closed on the server.
-  // Instead, throw a SqlException.  Since we did not receive a complete row, it is not safe to
-  // allow the application to continue to access the ResultSet, so we close it.
-  private void checkAndThrowReceivedEndqryrm () throws SqlException
-  {
-    // If we are in a split row, and before sending CNTQRY, check whether an ENDQRYRM
-    // has been received.
-    if (!netResultSet_.openOnServer_) {
-      SqlException sqlException = null;
-      int sqlcode = org.apache.derby.client.am.Utils.getSqlcodeFromSqlca (netResultSet_.queryTerminatingSqlca_);
-      if (sqlcode < 0)
-        sqlException = new SqlException (agent_.logWriter_, netResultSet_.queryTerminatingSqlca_);
-      else
-        sqlException = new SqlException (agent_.logWriter_, "Query processing has been terminated due to error on the server.");
-      try {
-        netResultSet_.closeX(); // the auto commit logic is in closeX()
-      }
-      catch (SqlException e) {
-        sqlException.setNextException (e);
-      }
-      throw sqlException;
-    }
-  }
-
-  private void checkAndThrowReceivedEndqryrm (int lastValidBytePositionBeforeFetch) throws SqlException
-  {
-    // if we have received more data in the dataBuffer_, just return.
-    if (lastValidBytePosition_ > lastValidBytePositionBeforeFetch)
-      return;
-    checkAndThrowReceivedEndqryrm ();
-  }
-
-  private int completeSplitRow () throws DisconnectException, SqlException
-  {
-    int lastValidBytePositionBeforeFetch = 0;
-    if (netResultSet_ != null && netResultSet_.scrollable_) {
-      lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-      netResultSet_.flowFetchToCompleteRowset ();
-    }
-    else {
-      // Shift partial row to the beginning of the dataBuffer
-      shiftPartialRowToBeginning ();
-      resetCurrentRowPosition ();
-      lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-      netResultSet_.flowFetch ();
-    }
-    return lastValidBytePositionBeforeFetch;
-  }
-
-  private int completeSplitRow (int index) throws DisconnectException, SqlException
-  {
-    int lastValidBytePositionBeforeFetch = 0;
-    if (netResultSet_ != null && netResultSet_.scrollable_) {
-      lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-      netResultSet_.flowFetchToCompleteRowset ();
-    }
-    else {
-      // Shift partial row to the beginning of the dataBuffer
-      shiftPartialRowToBeginning ();
-      adjustColumnOffsetsForColumnsPreviouslyCalculated (index);
-      resetCurrentRowPosition ();
-      lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-      netResultSet_.flowFetch ();
-    }
-    return lastValidBytePositionBeforeFetch;
-  }
-
-  private int[] allocateColumnDataPositionArray (int row)
-  {
-    int[] columnDataPosition;
-    if (columnDataPositionCache_.size() == row) {
-      columnDataPosition = new int[columns_];
-      columnDataPositionCache_.add (columnDataPosition);
-    }
-    else
-      columnDataPosition = (int[])columnDataPositionCache_.get(row);
-    return columnDataPosition;
-  }
-
-  private int[] allocateColumnDataComputedLengthArray (int row)
-  {
-    int[] columnDataComputedLength;
-    if (columnDataLengthCache_.size() == row) {
-      columnDataComputedLength = new int[columns_];
-      columnDataLengthCache_.add (columnDataComputedLength);
-    }
-    else
-      columnDataComputedLength = (int[])columnDataLengthCache_.get(row);
-    return columnDataComputedLength;
-  }
-
-  private boolean[] allocateColumnDataIsNullArray (int row)
-  {
-    boolean[] columnDataIsNull;
-    if (columnDataIsNullCache_.size() <= row) {
-      columnDataIsNull = new boolean[columns_];
-      columnDataIsNullCache_.add(columnDataIsNull);
-    }
-    else
-      columnDataIsNull = (boolean[])columnDataIsNullCache_.get(row);
-    return columnDataIsNull;
-  }
-
-  protected int getDecimalLength (int index)
-  {
-    return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2;
-  }
+    private void parseSQLCAXGRP(Typdef typdef, NetSqlca netSqlca) throws DisconnectException, SqlException {
+        if (readFdocaOneByte() == CodePoint.NULLDATA) {
+            netSqlca.setContainsSqlcax(false);
+            return;
+        }
+
+
+        //   SQLERRD1 to SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
+        int[] sqlerrd = new int[6];
+        for (int i = 0; i < sqlerrd.length; i++) {
+            sqlerrd[i] = readFdocaInt();
+        }
+
+        //   SQLWARN0 to SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
+        byte[] sqlwarn = readFdocaBytes(11);
+
+        // skip over the rdbnam for now
+        // SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
+        parseVCS(typdef);
+
+        //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
+        //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
+        int varcharLength = readFdocaTwoByteLength();  // mixed length
+        byte[] sqlerrmc = null;
+        int sqlerrmcCcsid = 0;
+        if (varcharLength != 0) {                    // if mixed
+            sqlerrmc = readFdocaBytes(varcharLength);      // read mixed bytes
+            sqlerrmcCcsid = typdef.getCcsidMbc();
+            skipFdocaBytes(2);                          // skip single length
+        } else {
+            varcharLength = readFdocaTwoByteLength();  // read single length
+            sqlerrmc = readFdocaBytes(varcharLength);     // read single bytes
+            sqlerrmcCcsid = typdef.getCcsidSbc();
+        }
+
+        netSqlca.setSqlerrd(sqlerrd);
+        netSqlca.setSqlwarnBytes(sqlwarn);
+        netSqlca.setSqlerrmcBytes(sqlerrmc, sqlerrmcCcsid);
+    }
+
+    // SQLDIAGGRP : FDOCA EARLY GROUP
+    private void parseSQLDIAGGRP() throws DisconnectException, SqlException {
+        if (readFdocaOneByte() == CodePoint.NULLDATA) {
+            return;
+        }
+
+        netAgent_.accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(netAgent_,
+                "parseSQLDIAGGRP not yet implemented"));
+    }
+
+    private String parseVCS(Typdef typdefInEffect) throws DisconnectException, SqlException {
+        return readFdocaString(readFdocaTwoByteLength(),
+                typdefInEffect.getCcsidSbcEncoding());
+    }
+
+    // This is not used for column data.
+    private String readFdocaString(int length, String encoding) throws DisconnectException, SqlException {
+        if (length == 0) {
+            return null;
+        }
+
+        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
+        // so there is no need to drive a flowFetch (continue query) request for singleton select.
+        if ((position_ + length) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow();
+
+            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
+            // throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+
+        String s = null;
+
+        try {
+            s = new String(dataBuffer_, position_, length, encoding);
+        } catch (java.io.UnsupportedEncodingException e) {
+            netAgent_.accumulateChainBreakingReadExceptionAndThrow(new org.apache.derby.client.am.DisconnectException(e,
+                    netAgent_,
+                    "encoding not supported!!"));
+        }
+
+        position_ += length;
+        return s;
+    }
+
+    void allocateColumnOffsetAndLengthArrays() {
+        columnDataPosition_ = new int[columns_];
+        columnDataComputedLength_ = new int[columns_];
+        isNull_ = new boolean[columns_];
+    }
+
+    void setBlocking(int queryProtocolType) {
+        if (queryProtocolType == CodePoint.LMTBLKPRC) {
+            blocking_ = true;
+        } else {
+            blocking_ = false;
+        }
+    }
+
+    protected byte[] findExtdtaData(int column) {
+        byte[] data = null;
+
+        // locate the EXTDTA bytes, if any
+        Integer key = new Integer(column);
+
+        if (extdtaPositions_.containsKey(key)) {
+            //  found, get the data
+            int extdtaQueuePosition = ((Integer) extdtaPositions_.get(key)).intValue();
+            data = (byte[]) (extdtaData_.get(extdtaQueuePosition));
+        }
+
+        return data;
+    }
+
+    public Blob getBlobColumn_(int column, Agent agent) throws SqlException {
+        int index = column - 1;
+        int dataOffset;
+        byte[] data;
+        Blob blob = null;
+
+        // locate the EXTDTA bytes, if any
+        data = findExtdtaData(column);
+
+        if (data != null) {
+            // data found
+            // set data offset based on the presence of a null indicator
+            if (!nullable_[index]) {
+                dataOffset = 0;
+            } else {
+                dataOffset = 1;
+            }
+
+            blob = new Blob(data, agent, dataOffset);
+        } else {
+            blob = new Blob(new byte[0], agent, 0);
+        }
+
+        return blob;
+    }
+
+
+    public Clob getClobColumn_(int column, Agent agent) throws SqlException {
+        int index = column - 1;
+        int dataOffset;
+        byte[] data;
+        Clob clob = null;
+
+        // locate the EXTDTA bytes, if any
+        data = findExtdtaData(column);
+
+        if (data != null) {
+            // data found
+            // set data offset based on the presence of a null indicator
+            if (!nullable_[index]) {
+                dataOffset = 0;
+            } else {
+                dataOffset = 1;
+            }
+            clob = new Clob(agent, data, charsetName_[index], dataOffset);
+        } else {
+            // the locator is not valid, it is a zero-length LOB
+            clob = new Clob(agent, "");
+        }
+
+        return clob;
+    }
+
+    public byte[] getClobBytes_(int column, int[] dataOffset /*output*/) throws SqlException {
+        int index = column - 1;
+        byte[] data = null;
+
+        // locate the EXTDTA bytes, if any
+        data = findExtdtaData(column);
+
+        if (data != null) {
+            // data found
+            // set data offset based on the presence of a null indicator
+            if (!nullable_[index]) {
+                dataOffset[0] = 0;
+            } else {
+                dataOffset[0] = 1;
+            }
+        }
+
+        return data;
+    }
+
+    // this is really an event-callback from NetStatementReply.parseSQLDTARDarray()
+    void initializeColumnInfoArrays(Typdef typdef,
+                                    int columnCount, int targetSqlamForTypdef) throws DisconnectException {
+        qrydscTypdef_ = typdef;
+
+        // Allocate  arrays to hold the descriptor information.
+        setNumberOfColumns(columnCount);
+        fdocaLength_ = new int[columnCount];
+        isGraphic_ = new boolean[columnCount];
+        typeToUseForComputingDataLength_ = new int[columnCount];
+        targetSqlamForTypdef_ = targetSqlamForTypdef;
+    }
+
+
+    int ensureSpaceForDataBuffer(int ddmLength) {
+        if (dataBuffer_ == null) {
+            allocateDataBuffer();
+        }
+        //super.resultSet.cursor.clearColumnDataOffsetsCache();
+        // Need to know how many bytes to ask from the Reply object,
+        // and handle the case where buffer is not big enough for all the bytes.
+        // Get the length in front of the code point first.
+
+        int bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
+
+        // Make sure the buffer has at least ddmLength amount of room left.
+        // If not, expand the buffer before calling the getQrydtaData() method.
+        if (bytesAvailableInDataBuffer < ddmLength) {
+
+            // Get a new buffer that is twice the size of the current buffer.
+            // Copy the contents from the old buffer to the new buffer.
+            int newBufferSize = 2 * dataBuffer_.length;
+
+            while (newBufferSize < ddmLength) {
+                newBufferSize = 2 * newBufferSize;
+            }
+
+            byte[] tempBuffer = new byte[newBufferSize];
+
+            System.arraycopy(dataBuffer_,
+                    0,
+                    tempBuffer,
+                    0,
+                    lastValidBytePosition_);
+
+            // Make the new buffer the dataBuffer.
+            dataBuffer_ = tempBuffer;
+
+            // Recalculate bytesAvailableInDataBuffer
+            bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
+        }
+        return bytesAvailableInDataBuffer;
+    }
+
+    protected void getMoreData_() throws SqlException {
+        // reset the dataBuffer_ before getting more data if cursor is foward-only.
+        // getMoreData() is only called in Cursor.next() when current position is
+        // equal to lastValidBytePosition_.
+        if (netResultSet_.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) {
+            resetDataBuffer();
+        }
+        netResultSet_.flowFetch();
+    }
+
+    public void nullDataForGC()       // memory leak fix
+    {
+        super.nullDataForGC();
+        qrydscTypdef_ = null;
+        typeToUseForComputingDataLength_ = null;
+        isGraphic_ = null;
+
+        if (extdtaPositions_ != null) {
+            extdtaPositions_.clear();
+        }
+        extdtaPositions_ = null;
+
+        if (extdtaData_ != null) {
+            extdtaData_.clear();
+        }
+        extdtaData_ = null;
+    }
+
+    // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD.
+    // This means some error has occurred on the server and the server is terminating the query.
+    // Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already
+    // been received.  If so, do not send CNTQRY because the cursor is already closed on the server.
+    // Instead, throw a SqlException.  Since we did not receive a complete row, it is not safe to
+    // allow the application to continue to access the ResultSet, so we close it.
+    private void checkAndThrowReceivedEndqryrm() throws SqlException {
+        // If we are in a split row, and before sending CNTQRY, check whether an ENDQRYRM
+        // has been received.
+        if (!netResultSet_.openOnServer_) {
+            SqlException sqlException = null;
+            int sqlcode = org.apache.derby.client.am.Utils.getSqlcodeFromSqlca(netResultSet_.queryTerminatingSqlca_);
+            if (sqlcode < 0) {
+                sqlException = new SqlException(agent_.logWriter_, netResultSet_.queryTerminatingSqlca_);
+            } else {
+                sqlException = new SqlException(agent_.logWriter_, "Query processing has been terminated due to error on the server.");
+            }
+            try {
+                netResultSet_.closeX(); // the auto commit logic is in closeX()
+            } catch (SqlException e) {
+                sqlException.setNextException(e);
+            }
+            throw sqlException;
+        }
+    }
+
+    private void checkAndThrowReceivedEndqryrm(int lastValidBytePositionBeforeFetch) throws SqlException {
+        // if we have received more data in the dataBuffer_, just return.
+        if (lastValidBytePosition_ > lastValidBytePositionBeforeFetch) {
+            return;
+        }
+        checkAndThrowReceivedEndqryrm();
+    }
+
+    private int completeSplitRow() throws DisconnectException, SqlException {
+        int lastValidBytePositionBeforeFetch = 0;
+        if (netResultSet_ != null && netResultSet_.scrollable_) {
+            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
+            netResultSet_.flowFetchToCompleteRowset();
+        } else {
+            // Shift partial row to the beginning of the dataBuffer
+            shiftPartialRowToBeginning();
+            resetCurrentRowPosition();
+            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
+            netResultSet_.flowFetch();
+        }
+        return lastValidBytePositionBeforeFetch;
+    }
+
+    private int completeSplitRow(int index) throws DisconnectException, SqlException {
+        int lastValidBytePositionBeforeFetch = 0;
+        if (netResultSet_ != null && netResultSet_.scrollable_) {
+            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
+            netResultSet_.flowFetchToCompleteRowset();
+        } else {
+            // Shift partial row to the beginning of the dataBuffer
+            shiftPartialRowToBeginning();
+            adjustColumnOffsetsForColumnsPreviouslyCalculated(index);
+            resetCurrentRowPosition();
+            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
+            netResultSet_.flowFetch();
+        }
+        return lastValidBytePositionBeforeFetch;
+    }
+
+    private int[] allocateColumnDataPositionArray(int row) {
+        int[] columnDataPosition;
+        if (columnDataPositionCache_.size() == row) {
+            columnDataPosition = new int[columns_];
+            columnDataPositionCache_.add(columnDataPosition);
+        } else {
+            columnDataPosition = (int[]) columnDataPositionCache_.get(row);
+        }
+        return columnDataPosition;
+    }
+
+    private int[] allocateColumnDataComputedLengthArray(int row) {
+        int[] columnDataComputedLength;
+        if (columnDataLengthCache_.size() == row) {
+            columnDataComputedLength = new int[columns_];
+            columnDataLengthCache_.add(columnDataComputedLength);
+        } else {
+            columnDataComputedLength = (int[]) columnDataLengthCache_.get(row);
+        }
+        return columnDataComputedLength;
+    }
+
+    private boolean[] allocateColumnDataIsNullArray(int row) {
+        boolean[] columnDataIsNull;
+        if (columnDataIsNullCache_.size() <= row) {
+            columnDataIsNull = new boolean[columns_];
+            columnDataIsNullCache_.add(columnDataIsNull);
+        } else {
+            columnDataIsNull = (boolean[]) columnDataIsNullCache_.get(row);
+        }
+        return columnDataIsNull;
+    }
+
+    protected int getDecimalLength(int index) {
+        return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2;
+    }
 
 }

Modified: incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java?rev=165585&r1=165584&r2=165585&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java (original)
+++ incubator/derby/code/trunk/java/client/org/apache/derby/client/net/NetDatabaseMetaData.java Sun May  1 23:25:59 2005
@@ -24,57 +24,54 @@
 import org.apache.derby.client.am.SqlException;
 
 
-public class NetDatabaseMetaData extends org.apache.derby.client.am.DatabaseMetaData
-{
+public class NetDatabaseMetaData extends org.apache.derby.client.am.DatabaseMetaData {
 
-  private final NetAgent netAgent_;
+    private final NetAgent netAgent_;
 
 
-  public NetDatabaseMetaData (NetAgent netAgent, NetConnection netConnection)
-  {
-    // Consider setting product level during parse
-    super (netAgent, netConnection, new ProductLevel (netConnection.productID_,
-                          netConnection.targetSrvclsnm_,
-                          netConnection.targetSrvrlslv_));
-    // Set up cheat-links
-    netAgent_ = netAgent;
-  }
-
-  //---------------------------call-down methods--------------------------------
-
-  public String getURL_ () throws SqlException
-  {
-    String urlProtocol;
-
-      urlProtocol = Configuration.jdbcDerbyNETProtocol;
-
-    return
-      urlProtocol +
-      connection_.serverNameIP_+
-      ":" +
-      connection_.portNumber_ +
-      "/" +
-      connection_.databaseName_;
-  }
-
-  //-----------------------------helper methods---------------------------------
-
-  // Set flags describing the level of support for this connection.
-  // Flags will be set based on manager level and/or specific product identifiers.
-  // Support for a specific server version can be set as follows. For example
-  // if (productLevel_.greaterThanOrEqualTo(11,1,0))
-  //  supportsTheBestThingEver = true
-  protected void computeFeatureSet_ ()
-  {
-    if (connection_.resultSetHoldability_ == 0)  // property not set
-      setDefaultResultSetHoldability ();
-
-  }
-
-
-  public void setDefaultResultSetHoldability ()
-  {
-	  connection_.resultSetHoldability_ = org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT;
-  }
+    public NetDatabaseMetaData(NetAgent netAgent, NetConnection netConnection) {
+        // Consider setting product level during parse
+        super(netAgent, netConnection, new ProductLevel(netConnection.productID_,
+                netConnection.targetSrvclsnm_,
+                netConnection.targetSrvrlslv_));
+        // Set up cheat-links
+        netAgent_ = netAgent;
+    }
+
+    //---------------------------call-down methods--------------------------------
+
+    public String getURL_() throws SqlException {
+        String urlProtocol;
+
+        urlProtocol = Configuration.jdbcDerbyNETProtocol;
+
+        return
+                urlProtocol +
+                connection_.serverNameIP_ +
+                ":" +
+                connection_.portNumber_ +
+                "/" +
+                connection_.databaseName_;
+    }
+
+    //-----------------------------helper methods---------------------------------
+
+    // Set flags describing the level of support for this connection.
+    // Flags will be set based on manager level and/or specific product identifiers.
+    // Support for a specific server version can be set as follows. For example
+    // if (productLevel_.greaterThanOrEqualTo(11,1,0))
+    //  supportsTheBestThingEver = true
+    protected void computeFeatureSet_() {
+        if (connection_.resultSetHoldability_ == 0)  // property not set
+        {
+            setDefaultResultSetHoldability();
+        }
+
+    }
+
+
+    public void setDefaultResultSetHoldability() {
+        connection_.resultSetHoldability_ = org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT;
+    }
 
 }