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;
+ }
}