EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.client.net]

COVERAGE SUMMARY FOR SOURCE FILE [NetCursor.java]

nameclass, %method, %block, %line, %
NetCursor.java100% (1/1)82%  (36/44)71%  (1147/1621)67%  (252.4/374)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class NetCursor100% (1/1)82%  (36/44)71%  (1147/1621)67%  (252.4/374)
NetCursor (NetAgent): void 100% (1/1)100% (26/26)100% (8/8)
NetCursor (NetAgent, int): void 100% (1/1)100% (17/17)100% (6/6)
adjustColumnOffsetsForColumnsPreviouslyCalculated (int): void 100% (1/1)100% (17/17)100% (3/3)
allocateColumnDataComputedLengthArray (int): int [] 100% (1/1)100% (23/23)100% (5/5)
allocateColumnDataIsNullArray (int): boolean [] 100% (1/1)100% (23/23)100% (5/5)
allocateColumnDataPositionArray (int): int [] 100% (1/1)100% (23/23)100% (5/5)
allocateColumnOffsetAndLengthArrays (): void 0%   (0/1)0%   (0/16)0%   (0/4)
allocateDataBuffer (): void 0%   (0/1)0%   (0/21)0%   (0/7)
allocateDataBuffer (int): void 0%   (0/1)0%   (0/5)0%   (0/2)
calculateColumnOffsetsForRow_ (int): boolean 100% (1/1)69%  (295/428)76%  (66.4/87)
calculateLobColumnPositionsForRow (): void 100% (1/1)100% (30/30)100% (5/5)
checkAndThrowReceivedEndqryrm (): void 100% (1/1)12%  (5/43)17%  (2/12)
checkAndThrowReceivedEndqryrm (int): void 100% (1/1)62%  (5/8)50%  (2/4)
clearLobData_ (): void 100% (1/1)100% (7/7)100% (3/3)
completeSplitRow (): int 0%   (0/1)0%   (0/28)0%   (0/9)
completeSplitRow (int): int 100% (1/1)100% (31/31)100% (10/10)
ensureSpaceForDataBuffer (int): int 0%   (0/1)0%   (0/52)0%   (0/12)
findExtdtaData (int): byte [] 100% (1/1)100% (27/27)100% (6/6)
getBlobColumn_ (int, Agent): Blob 100% (1/1)100% (40/40)100% (10/10)
getClobBytes_ (int, int []): byte [] 0%   (0/1)0%   (0/28)0%   (0/8)
getClobColumn_ (int, Agent): Clob 100% (1/1)100% (42/42)100% (10/10)
getDecimalLength (int): int 100% (1/1)100% (13/13)100% (1/1)
getMoreData_ (): void 100% (1/1)100% (11/11)100% (4/4)
initializeColumnInfoArrays (Typdef, int, int): void 100% (1/1)100% (22/22)100% (7/7)
isDataBufferNull (): boolean 0%   (0/1)0%   (0/7)0%   (0/3)
isNonTrivialDataLob (int): boolean 100% (1/1)97%  (86/89)93%  (14/15)
nullDataForGC (): void 100% (1/1)100% (30/30)100% (11/11)
parseSQLCAGRP (Typdef): NetSqlca 100% (1/1)100% (37/37)100% (9/9)
parseSQLCARD (Typdef): NetSqlca 100% (1/1)100% (4/4)100% (1/1)
parseSQLCAXGRP (Typdef, NetSqlca): void 100% (1/1)81%  (60/74)77%  (17/22)
parseSQLDIAGGRP (): void 100% (1/1)33%  (5/15)50%  (2/4)
parseVCS (Typdef): String 100% (1/1)100% (7/7)100% (1/1)
readFdocaBytes (int): byte [] 100% (1/1)80%  (32/40)62%  (5/8)
readFdocaInt (): int 100% (1/1)72%  (21/29)57%  (4/7)
readFdocaOneByte (): int 100% (1/1)69%  (18/26)40%  (2/5)
readFdocaOneByte (int): int 100% (1/1)67%  (18/27)40%  (2/5)
readFdocaString (int, String): String 100% (1/1)8%   (4/51)15%  (2/13)
readFdocaTwoByteLength (): int 100% (1/1)82%  (37/45)40%  (2/5)
readFdocaTwoByteLength (int): int 100% (1/1)80%  (37/46)40%  (2/5)
resetCurrentRowPosition (): void 100% (1/1)100% (4/4)100% (2/2)
setBlocking (int): void 0%   (0/1)0%   (0/11)0%   (0/4)
shiftPartialRowToBeginning (): void 100% (1/1)100% (51/51)100% (9/9)
skipFdocaBytes (int): int 100% (1/1)65%  (15/23)50%  (3/6)
skipFdocaBytes (int, int): int 100% (1/1)100% (24/24)100% (6/6)

1/*
2 
3   Derby - Class org.apache.derby.client.net.NetCursor
4 
5   Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19*/
20 
21package org.apache.derby.client.net;
22 
23import org.apache.derby.client.am.Agent;
24import org.apache.derby.client.am.Blob;
25import org.apache.derby.client.am.Clob;
26import org.apache.derby.client.am.DisconnectException;
27import org.apache.derby.client.am.SignedBinary;
28import org.apache.derby.client.am.SqlException;
29import org.apache.derby.client.am.ClientMessageId;
30import org.apache.derby.client.am.SqlWarning;
31import org.apache.derby.client.am.Types;
32import org.apache.derby.client.am.SqlCode;
33import org.apache.derby.shared.common.reference.SQLState;
34import org.apache.derby.shared.common.sanity.SanityManager;
35 
36public class NetCursor extends org.apache.derby.client.am.Cursor {
37 
38    NetResultSet netResultSet_;
39    NetAgent netAgent_;
40 
41    Typdef qrydscTypdef_;
42 
43    int targetSqlamForTypdef_;
44 
45 
46    // override column meta data
47    int numMddOverrides_;
48    int maximumRowSize_;
49    boolean blocking_;  // if true, multiple rows may be "blocked" in a single reply
50 
51    // Raw fdoca column meta data.
52    int[] typeToUseForComputingDataLength_;
53    boolean[] isGraphic_;
54 
55    // key = column position, value = index into extdtaData_
56    java.util.HashMap extdtaPositions_;
57    java.util.ArrayList extdtaData_; // queue to hold EXTDTA data that hasn't been correlated to its column #
58 
59 
60    boolean rtnextrow_ = true;
61 
62    /** Flag indicating whether the result set on the server is
63     * implicitly closed when end-of-data is received. */
64    private boolean qryclsimpEnabled_;
65 
66    //-----------------------------constants--------------------------------------
67 
68    //---------------------constructors/finalizer---------------------------------
69 
70    NetCursor(NetAgent netAgent) {
71        super(netAgent);
72        netAgent_ = netAgent;
73        numMddOverrides_ = 0;
74        maximumRowSize_ = 0;
75        extdtaPositions_ = new java.util.HashMap();
76        extdtaData_ = new java.util.ArrayList();
77    }
78 
79    NetCursor(NetAgent netAgent,
80              int qryprctyp)  //protocolType, CodePoint.FIXROWPRC | CodePoint.LMTBLKPRC
81    {
82        this(netAgent);
83        if (qryprctyp == CodePoint.FIXROWPRC) {
84            blocking_ = false;
85        } else if (qryprctyp == CodePoint.LMTBLKPRC) {
86            blocking_ = true;
87        }
88    }
89    //-----------------------------parsing the data buffer------------------------
90 
91    /**
92     * Calculate the column offsets for a row.
93     * <p>
94     * Pseudo-code:
95     * <ol>
96     * <li>parse thru the current row in dataBuffer computing column
97     * offsets</li>
98     * <li>if (we hit the super.lastValidBytePosition, ie. encounter
99     * partial row)
100     *   <ol>
101     *     <li>shift partial row bytes to beginning of dataBuffer
102     *     (this.shiftPartialRowToBeginning())</li>
103     *     <li>reset current row position (also done by
104     *     this.shiftPartialRowToBeginning())</li>
105     *     <li>send and recv continue-query into commBuffer
106     *     (rs.flowContinueQuery())</li>
107     *     <li>parse commBuffer up to QRYDTA
108     *     (rs.flowContinueQuery())</li>
109     *     <li>copy query data from reply's commBuffer to our
110     *     dataBuffer (this.copyQrydta())</li>
111     *   </ol>
112     * </ol>
113     *
114     * @param rowIndex row index
115     * @param allowServerFetch if true, allow fetching more data from
116     * server
117     * @return <code>true</code> if the current row position is a
118     * valid row position.
119     * @exception SqlException
120     * @exception DisconnectException
121     */
122    protected
123        boolean calculateColumnOffsetsForRow_(int rowIndex,
124                                              boolean allowServerFetch)
125        throws SqlException, DisconnectException
126    {
127        int daNullIndicator = CodePoint.NULLDATA;
128        int colNullIndicator = CodePoint.NULLDATA;
129        int length;
130 
131        int[] columnDataPosition = null;
132        int[] columnDataComputedLength = null;
133        boolean[] columnDataIsNull = null;
134        boolean receivedDeleteHoleWarning = false;
135        boolean receivedRowUpdatedWarning = false;
136 
137        if ((position_ == lastValidBytePosition_) &&
138                (netResultSet_ != null) && (netResultSet_.scrollable_)) {
139            return false;
140        }
141 
142        if (hasLobs_) {
143            extdtaPositions_.clear();  // reset positions for this row
144        }
145 
146        NetSqlca[] netSqlca = this.parseSQLCARD(qrydscTypdef_);
147 
148        if (netSqlca != null) {
149            for (int i=0;i<netSqlca.length; i++) {
150                int sqlcode = netSqlca[i].getSqlCode();
151                if (sqlcode < 0) {
152                    throw new SqlException(netAgent_.logWriter_, 
153                            netSqlca[i]);
154                } else {
155                    if (sqlcode == SqlCode.END_OF_DATA.getCode()) {
156                        setAllRowsReceivedFromServer(true);
157                        if (netResultSet_ != null && 
158                                netSqlca[i].containsSqlcax()) {
159                            netResultSet_.setRowCountEvent(
160                                    netSqlca[i].getRowCount(
161                                        qrydscTypdef_));
162                        }
163                    } else if (netResultSet_ != null && sqlcode > 0) {
164                        String sqlState = netSqlca[i].getSqlState();
165                        if (!sqlState.equals(SQLState.ROW_DELETED) && 
166                                !sqlState.equals(SQLState.ROW_UPDATED)) {
167                            netResultSet_.accumulateWarning(
168                                    new SqlWarning(agent_.logWriter_, 
169                                        netSqlca[i]));
170                        } else {
171                            receivedDeleteHoleWarning 
172                                    |= sqlState.equals(SQLState.ROW_DELETED);
173                            receivedRowUpdatedWarning 
174                                    |= sqlState.equals(SQLState.ROW_UPDATED);
175                        }
176                    }
177                }
178            }
179        }
180 
181        setIsUpdataDeleteHole(rowIndex, receivedDeleteHoleWarning);
182        setIsRowUpdated(receivedRowUpdatedWarning);
183        
184        // If we don't have at least one byte in the buffer for the DA null indicator,
185        // then we need to send a CNTQRY request to fetch the next block of data.
186        // Read the DA null indicator.
187        daNullIndicator = readFdocaOneByte();
188 
189        // In the case for held cursors, the +100 comes back as part of the QRYDTA, and as
190        // we are parsing through the row that contains the SQLCA with +100, we mark the
191        // nextRowPosition_ which is the lastValidBytePosition_, but we don't mark the
192        // currentRowPosition_ until the next time next() is called causing the check
193        // cursor_.currentRowPositionIsEqualToNextRowPosition () to fail in getRow() and thus
194        // not returning 0 when it should. So we need to mark the current row position immediately
195        // in order for getRow() to be able to pick it up.
196 
197        // markNextRowPosition() is called again once this method returns, but it is ok
198        // since it's only resetting nextRowPosition_ to position_ and position_ will
199        // not change again from this point.
200 
201        if (allRowsReceivedFromServer() &&
202            (position_ == lastValidBytePosition_)) {
203            markNextRowPosition();
204            makeNextRowPositionCurrent();
205            return false;
206        }
207 
208        // If data flows....
209        if (daNullIndicator == 0x0) {
210 
211            if (SanityManager.DEBUG && receivedDeleteHoleWarning) {
212                SanityManager.THROWASSERT("Delete hole warning received: nulldata expected");
213            }
214            incrementRowsReadEvent();
215 
216            // netResultSet_ is null if this method is invoked from Lob.position()
217            // If row has exceeded the size of the ArrayList, new up a new int[] and add it to the
218            // ArrayList, otherwise just reuse the int[].
219            if (netResultSet_ != null && netResultSet_.scrollable_) {
220                columnDataPosition = allocateColumnDataPositionArray(rowIndex);
221                columnDataComputedLength = allocateColumnDataComputedLengthArray(rowIndex);
222                columnDataIsNull = allocateColumnDataIsNullArray(rowIndex);
223                // Since we are no longer setting the int[]'s to null for a delete/update hole, we need
224                // another way of keeping track of the delete/update holes.
225                setIsUpdataDeleteHole(rowIndex, false);
226            } else {
227                // Use the arrays defined on the Cursor for forward-only cursors.
228                // can they ever be null
229                if (columnDataPosition_ == null || columnDataComputedLength_ == null || isNull_ == null) {
230                    allocateColumnOffsetAndLengthArrays();
231                }
232                columnDataPosition = columnDataPosition_;
233                columnDataComputedLength = columnDataComputedLength_;
234                columnDataIsNull = isNull_;
235            }
236 
237            // Loop through the columns
238            for (int index = 0; index < columns_; index++) {
239                // If column is nullable, read the 1-byte null indicator.
240                if (nullable_[index])
241                // Need to pass the column index so all previously calculated offsets can be
242                // readjusted if the query block splits on a column null indicator.
243 
244                // null indicators from FD:OCA data
245                // 0 to 127: a data value will flow.
246                // -1 to -128: no data value will flow.
247                {
248                    colNullIndicator = readFdocaOneByte(index);
249                }
250 
251                // If non-null column data
252                if (!nullable_[index] || (colNullIndicator >= 0 && colNullIndicator <= 127)) {
253 
254                    // Set the isNull indicator to false
255                    columnDataIsNull[index] = false;
256 
257                    switch (typeToUseForComputingDataLength_[index]) {
258                    // for fixed length data
259                    case Typdef.FIXEDLENGTH:
260                        columnDataPosition[index] = position_;
261                        if (isGraphic_[index]) {
262                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
263                        } else {
264                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
265                        }
266                        break;
267 
268                        // for variable character string and variable byte string,
269                        // there are 2-byte of length in front of the data
270                    case Typdef.TWOBYTELENGTH:
271                        columnDataPosition[index] = position_;
272                        length = readFdocaTwoByteLength(index);
273                        // skip length + the 2-byte length field
274                        if (isGraphic_[index]) {
275                            columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 2;
276                        } else {
277                            columnDataComputedLength[index] = skipFdocaBytes(length, index) + 2;
278                        }
279                        break;
280 
281                        // For decimal columns, determine the precision, scale, and the representation
282                    case Typdef.DECIMALLENGTH:
283                        columnDataPosition[index] = position_;
284                        columnDataComputedLength[index] = skipFdocaBytes(getDecimalLength(index), index);
285                        break;
286 
287                    case Typdef.LOBLENGTH:
288                        columnDataPosition[index] = position_;
289                        columnDataComputedLength[index] = this.skipFdocaBytes(fdocaLength_[index] & 0x7fff, index);
290                        break;
291 
292                        // for short variable character string and short variable byte string,
293                        // there is a 1-byte length in front of the data
294                    case Typdef.ONEBYTELENGTH:
295                        columnDataPosition[index] = position_;
296                        length = readFdocaOneByte(index);
297                        // skip length + the 1-byte length field
298                        if (isGraphic_[index]) {
299                            columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 1;
300                        } else {
301                            columnDataComputedLength[index] = skipFdocaBytes(length, index) + 1;
302                        }
303                        break;
304 
305                    default:
306                        columnDataPosition[index] = position_;
307                        if (isGraphic_[index]) {
308                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
309                        } else {
310                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
311                        }
312                        break;
313                    }
314                } else if ((colNullIndicator & 0x80) == 0x80) {
315                    // Null data. Set the isNull indicator to true.
316                    columnDataIsNull[index] = true;
317                }
318            }
319 
320            // set column offsets for the current row.
321            columnDataPosition_ = columnDataPosition;
322            columnDataComputedLength_ = columnDataComputedLength;
323            isNull_ = columnDataIsNull;
324 
325            if (!allRowsReceivedFromServer()) {
326                calculateLobColumnPositionsForRow();
327                // Flow another CNTQRY if we are blocking, are using rtnextrow, and expect
328                // non-trivial EXTDTAs for forward only cursors.  Note we do not support
329                // EXTDTA retrieval for scrollable cursors.
330                // if qryrowset was sent on excsqlstt for a sp call, which is only the case
331                if (blocking_ && rtnextrow_ &&
332                    !netResultSet_.scrollable_ &&
333                    !extdtaPositions_.isEmpty()) {
334                    if (allowServerFetch) {
335                        netResultSet_.flowFetch();
336                    } else {
337                        return false;
338                    }
339                }
340            }
341        } else {
342            if (netResultSet_ != null && netResultSet_.scrollable_) {
343                if (receivedDeleteHoleWarning) {
344                    setIsUpdataDeleteHole(rowIndex, true);
345                } else {
346                    if (SanityManager.DEBUG) {
347                        // Invariant: for SUR, we introduced the warning
348                        // in addition to null data.
349                        SanityManager
350                            .THROWASSERT("Delete hole warning expected");
351                    }
352                }
353            }
354        }
355 
356        // If blocking protocol is used, we could have already received an ENDQRYRM,
357        // which sets allRowsReceivedFromServer_ to true.  It's safe to assume that all of
358        // our QRYDTA's have been successfully copied to the dataBuffer.  And even though
359        // the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through
360        // the data in the dataBuffer.
361        // But in the case where fixed row protocol is used,
362        if (!blocking_ && allRowsReceivedFromServer() &&
363            daNullIndicator == 0xFF) {
364            return false;
365        } else {
366            return true;
367        }
368    }
369 
370    /**
371     * Scan the data buffer to see if end of data (SQL state 02000)
372     * has been received. This method should only be called when the
373     * cursor is being closed since the pointer to the current row can
374     * be modified.
375     *
376     * @exception SqlException
377     */
378    void scanDataBufferForEndOfData() throws SqlException {
379        while (!allRowsReceivedFromServer() &&
380               (position_ != lastValidBytePosition_)) {
381            stepNext(false);
382        }
383    }
384 
385    protected boolean isDataBufferNull() {
386        if (dataBuffer_ == null) {
387            return true;
388        } else {
389            return false;
390        }
391    }
392 
393    protected void allocateDataBuffer() {
394        int length;
395        if (maximumRowSize_ > DssConstants.MAX_DSS_LEN) {
396            length = maximumRowSize_;
397        } else {
398            length = DssConstants.MAX_DSS_LEN;
399        }
400 
401        dataBuffer_ = new byte[length];
402        position_ = 0;
403        lastValidBytePosition_ = 0;
404    }
405 
406    protected void allocateDataBuffer(int length) {
407        dataBuffer_ = new byte[length];
408    }
409 
410 
411    private int readFdocaInt() throws org.apache.derby.client.am.DisconnectException, SqlException {
412        if ((position_ + 4) > lastValidBytePosition_) {
413            // Check for ENDQRYRM, throw SqlException if already received one.
414            checkAndThrowReceivedEndqryrm();
415 
416            // Send CNTQRY to complete the row/rowset.
417            int lastValidByteBeforeFetch = completeSplitRow();
418 
419            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
420            // throw a SqlException for the ENDQRYRM.
421            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
422        }
423 
424        int i = SignedBinary.getInt(dataBuffer_, position_);
425        position_ += 4;
426        return i;
427    }
428 
429    // Reads 8-bytes from the dataBuffer from the current position.
430    // If position is already at the end of the buffer, send CNTQRY to get more 
431    // data.
432    private long readFdocaLong() throws 
433            org.apache.derby.client.am.DisconnectException, SqlException {
434        if ((position_ + 8) > lastValidBytePosition_) {
435            // Check for ENDQRYRM, throw SqlException if already received one.
436            checkAndThrowReceivedEndqryrm();
437 
438            // Send CNTQRY to complete the row/rowset.
439            int lastValidByteBeforeFetch = completeSplitRow();
440 
441            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was 
442            // received, throw a SqlException for the ENDQRYRM.
443            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
444        }
445 
446        long i = SignedBinary.getLong(dataBuffer_, position_);
447        position_ += 8;
448        return i;
449    }
450        
451    // Reads 1-byte from the dataBuffer from the current position.
452    // If position is already at the end of the buffer, send CNTQRY to get more data.
453    private int readFdocaOneByte() throws org.apache.derby.client.am.DisconnectException, SqlException {
454        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
455        // so there is no need to drive a flowFetch (continue query) request for singleton select.
456        if (position_ == lastValidBytePosition_) {
457            // Check for ENDQRYRM, throw SqlException if already received one.
458            checkAndThrowReceivedEndqryrm();
459 
460            // Send CNTQRY to complete the row/rowset.
461            int lastValidByteBeforeFetch = completeSplitRow();
462 
463            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
464            // throw a SqlException for the ENDQRYRM.
465            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
466        }
467        return dataBuffer_[position_++] & 0xff;
468    }
469 
470    // Reads 1-byte from the dataBuffer from the current position.
471    // If position is already at the end of the buffer, send CNTQRY to get more data.
472    private int readFdocaOneByte(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
473        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
474        // so there is no need to drive a flowFetch (continue query) request for singleton select.
475        if (position_ == lastValidBytePosition_) {
476            // Check for ENDQRYRM, throw SqlException if already received one.
477            checkAndThrowReceivedEndqryrm();
478 
479            // Send CNTQRY to complete the row/rowset.
480            int lastValidByteBeforeFetch = completeSplitRow(index);
481 
482            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
483            // throw a SqlException for the ENDQRYRM.
484            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
485        }
486        return dataBuffer_[position_++] & 0xff;
487    }
488 
489    // Reads <i>length</i> number of bytes from the dataBuffer starting from the
490    // current position.  Returns a new byte array which contains the bytes read.
491    // If current position plus length goes past the lastValidBytePosition, send
492    // CNTQRY to get more data.
493    private byte[] readFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
494        byte[] b = new byte[length];
495        ;
496 
497        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
498        // so there is no need to drive a flowFetch (continue query) request for singleton select.
499        if ((position_ + length) > lastValidBytePosition_) {
500            // Check for ENDQRYRM, throw SqlException if already received one.
501            checkAndThrowReceivedEndqryrm();
502 
503            // Send CNTQRY to complete the row/rowset.
504            int lastValidByteBeforeFetch = completeSplitRow();
505 
506            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
507            // throw a SqlException for the ENDQRYRM.
508            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
509        }
510 
511        for (int i = 0; i < length; i++) {
512            b[i] = dataBuffer_[position_++];
513        }
514 
515        return b;
516    }
517 
518    // Reads 2-bytes from the dataBuffer starting from the current position, and
519    // returns an integer constructed from the 2-bytes.  If current position plus
520    // 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data.
521    private int readFdocaTwoByteLength() throws org.apache.derby.client.am.DisconnectException, SqlException {
522        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
523        // so there is no need to drive a flowFetch (continue query) request for singleton select.
524        if ((position_ + 2) > lastValidBytePosition_) {
525            // Check for ENDQRYRM, throw SqlException if already received one.
526            checkAndThrowReceivedEndqryrm();
527 
528            // Send CNTQRY to complete the row/rowset.
529            int lastValidByteBeforeFetch = completeSplitRow();
530 
531            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
532            // throw a SqlException for the ENDQRYRM.
533            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
534        }
535 
536        return
537                ((dataBuffer_[position_++] & 0xff) << 8) +
538                ((dataBuffer_[position_++] & 0xff) << 0);
539    }
540 
541    private int readFdocaTwoByteLength(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
542        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
543        // so there is no need to drive a flowFetch (continue query) request for singleton select.
544        if ((position_ + 2) > lastValidBytePosition_) {
545            // Check for ENDQRYRM, throw SqlException if already received one.
546            checkAndThrowReceivedEndqryrm();
547 
548            // Send CNTQRY to complete the row/rowset.
549            int lastValidByteBeforeFetch = completeSplitRow(index);
550 
551            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
552            // throw a SqlException for the ENDQRYRM.
553            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
554        }
555 
556        return
557                ((dataBuffer_[position_++] & 0xff) << 8) +
558                ((dataBuffer_[position_++] & 0xff) << 0);
559    }
560 
561    // Check if position plus length goes past the lastValidBytePosition.
562    // If so, send CNTQRY to get more data.
563    // length - number of bytes to skip
564    // returns the number of bytes skipped
565    private int skipFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
566        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
567        // so there is no need to drive a flowFetch (continue query) request for singleton select.
568        if ((position_ + length) > lastValidBytePosition_) {
569            // Check for ENDQRYRM, throw SqlException if already received one.
570            checkAndThrowReceivedEndqryrm();
571 
572            // Send CNTQRY to complete the row/rowset.
573            int lastValidByteBeforeFetch = completeSplitRow();
574 
575            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
576            // throw a SqlException for the ENDQRYRM.
577            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
578        }
579        position_ += length;
580        return length;
581    }
582 
583    private int skipFdocaBytes(int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
584        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
585        // so there is no need to drive a flowFetch (continue query) request for singleton select.
586        if ((position_ + length) > lastValidBytePosition_) {
587            // Check for ENDQRYRM, throw SqlException if already received one.
588            checkAndThrowReceivedEndqryrm();
589 
590            // Send CNTQRY to complete the row/rowset.
591            int lastValidByteBeforeFetch = completeSplitRow(index);
592 
593            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
594            // throw a SqlException for the ENDQRYRM.
595            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
596        }
597 
598        position_ += length;
599        return length;
600    }
601 
602    // Shift partial row bytes to beginning of dataBuffer,
603    // and resets current row position, and lastValidBytePosition.
604    // When we shift partial row, we'll have to recalculate column offsets
605    // up to this column.
606    private void shiftPartialRowToBeginning() {
607        // Get the length to shift from the beginning of the partial row.
608        int length = lastValidBytePosition_ - currentRowPosition_;
609 
610        // shift the data in the dataBufferStream
611        dataBufferStream_.reset();
612        if (dataBuffer_ != null) {
613            dataBufferStream_.write(dataBuffer_, currentRowPosition_, length);
614        }
615 
616        for (int i = 0; i < length; i++) {
617            dataBuffer_[i] = dataBuffer_[currentRowPosition_ + i];
618        }
619 
620        position_ = length - (lastValidBytePosition_ - position_);
621        lastValidBytePosition_ = length;
622    }
623 
624    private void adjustColumnOffsetsForColumnsPreviouslyCalculated(int index) {
625        for (int j = 0; j <= index; j++) {
626            columnDataPosition_[j] -= currentRowPosition_;
627        }
628    }
629 
630    private void resetCurrentRowPosition() {
631        currentRowPosition_ = 0;
632    }
633 
634    // Calculates the column index for Lob objects constructed from EXTDTA data.
635    // Describe information isn't sufficient because we have to check
636    // for trivial values (nulls or zero-length) and exclude them.
637    void calculateLobColumnPositionsForRow() {
638        int currentPosition = 0;
639 
640        for (int i = 0; i < columns_; i++) {
641            if (isNonTrivialDataLob(i))
642            // key = column position, data = index to corresponding data in extdtaData_
643            // ASSERT: the server always returns the EXTDTA objects in ascending order
644            {
645                extdtaPositions_.put(new Integer(i + 1), new Integer(currentPosition++));
646            }
647        }
648    }
649 
650    // prereq: the base data for the cursor has been processed for offsets and lengths
651    boolean isNonTrivialDataLob(int index) {
652        long length = 0L;
653 
654        if (isNull_[index] ||
655                (jdbcTypes_[index] != Types.BLOB &&
656                jdbcTypes_[index] != Types.CLOB)) {
657            return false;
658        }
659 
660        int position = columnDataPosition_[index];
661 
662        // if the high-order bit is set, length is unknown -> set value to x'FF..FF'
663        if (((dataBuffer_[position]) & 0x80) == 0x80) {
664            length = -1;
665        } else {
666 
667            byte[] lengthBytes = new byte[columnDataComputedLength_[index]];
668            byte[] longBytes = new byte[8];
669 
670            System.arraycopy(dataBuffer_,
671                    position,
672                    lengthBytes,
673                    0,
674                    columnDataComputedLength_[index]);
675 
676            // right-justify for BIG ENDIAN
677            int j = 0;
678            for (int i = 8 - columnDataComputedLength_[index]; i < 8; i++) {
679                longBytes[i] = lengthBytes[j];
680                j++;
681            }
682            length = SignedBinary.getLong(longBytes, 0);
683        }
684        return (length != 0L) ? true : false;
685    }
686 
687    protected void clearLobData_() {
688        extdtaData_.clear();
689        extdtaPositions_.clear();
690    }
691 
692    // SQLCARD : FDOCA EARLY ROW
693    // SQL Communications Area Row Description
694    //
695    // FORMAT FOR ALL SQLAM LEVELS
696    //   SQLCAGRP; GROUP LID 0x54; ELEMENT TAKEN 0(all); REP FACTOR 1
697    NetSqlca[] parseSQLCARD(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
698        return parseSQLCAGRP(typdef);
699    }
700 
701    // SQLCAGRP : FDOCA EARLY GROUP
702    // SQL Communcations Area Group Description
703    //
704    // FORMAT FOR SQLAM <= 6
705    //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
706    //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
707    //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
708    //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
709    //
710    // FORMAT FOR SQLAM >= 7
711    //   SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
712    //   SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
713    //   SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
714    //   SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
715    //   SQLDIAGGRP; PROTOCOL TYPE N-GDA; ENVLID 0x56; Length Override 0
716    private NetSqlca[] parseSQLCAGRP(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
717        if (readFdocaOneByte() == CodePoint.NULLDATA) {
718            return null;
719        }
720        int sqlcode = readFdocaInt();
721        byte[] sqlstate = readFdocaBytes(5);
722        byte[] sqlerrproc = readFdocaBytes(8);
723        NetSqlca netSqlca = new NetSqlca(netAgent_.netConnection_, sqlcode, sqlstate, sqlerrproc);
724 
725        parseSQLCAXGRP(typdef, netSqlca);
726 
727        NetSqlca[] sqlCa = parseSQLDIAGGRP();
728 
729        NetSqlca[] ret_val;
730        if (sqlCa != null) {
731            ret_val = new NetSqlca[sqlCa.length + 1];
732            System.arraycopy(sqlCa, 0, ret_val, 1, sqlCa.length);
733        } else {
734            ret_val = new NetSqlca[1];
735        }
736        ret_val[0] = netSqlca;
737        
738        return ret_val;
739    }
740 
741    // SQLCAXGRP : EARLY FDOCA GROUP
742    // SQL Communications Area Exceptions Group Description
743    //
744    // FORMAT FOR SQLAM <= 6
745    //   SQLRDBNME; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 18
746    //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
747    //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
748    //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
749    //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
750    //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
751    //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
752    //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
753    //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
754    //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
755    //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
756    //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
757    //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
758    //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
759    //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
760    //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
761    //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
762    //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
763    //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
764    //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
765    //
766    // FORMAT FOR SQLAM >= 7
767    //   SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
768    //   SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
769    //   SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
770    //   SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
771    //   SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
772    //   SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
773    //   SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
774    //   SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
775    //   SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
776    //   SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
777    //   SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
778    //   SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
779    //   SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
780    //   SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
781    //   SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
782    //   SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
783    //   SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
784    //   SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
785    //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
786    //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
787    private void parseSQLCAXGRP(Typdef typdef, NetSqlca netSqlca) throws DisconnectException, SqlException {
788        if (readFdocaOneByte() == CodePoint.NULLDATA) {
789            netSqlca.setContainsSqlcax(false);
790            return;
791        }
792 
793 
794        //   SQLERRD1 to SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
795        int[] sqlerrd = new int[6];
796        for (int i = 0; i < sqlerrd.length; i++) {
797            sqlerrd[i] = readFdocaInt();
798        }
799 
800        //   SQLWARN0 to SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
801        byte[] sqlwarn = readFdocaBytes(11);
802 
803        // skip over the rdbnam for now
804        // SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
805        parseVCS(typdef);
806 
807        //   SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
808        //   SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
809        int varcharLength = readFdocaTwoByteLength();  // mixed length
810        byte[] sqlerrmc = null;
811        int sqlerrmcCcsid = 0;
812        if (varcharLength != 0) {                    // if mixed
813            sqlerrmc = readFdocaBytes(varcharLength);      // read mixed bytes
814            sqlerrmcCcsid = typdef.getCcsidMbc();
815            skipFdocaBytes(2);                          // skip single length
816        } else {
817            varcharLength = readFdocaTwoByteLength();  // read single length
818            sqlerrmc = readFdocaBytes(varcharLength);     // read single bytes
819            sqlerrmcCcsid = typdef.getCcsidSbc();
820        }
821 
822        netSqlca.setSqlerrd(sqlerrd);
823        netSqlca.setSqlwarnBytes(sqlwarn);
824        netSqlca.setSqlerrmcBytes(sqlerrmc, sqlerrmcCcsid);
825    }
826 
827    // SQLDIAGGRP : FDOCA EARLY GROUP
828    private NetSqlca[] parseSQLDIAGGRP() throws DisconnectException, SqlException {
829        if (readFdocaOneByte() == CodePoint.NULLDATA) {
830            return null;
831        }
832 
833        parseSQLDIAGSTT();
834        NetSqlca[] sqlca = parseSQLDIAGCI();
835        parseSQLDIAGCN();
836 
837        return sqlca;
838    }
839 
840    // SQL Diagnostics Statement Group Description - Identity 0xD3
841    // NULLDATA will be received for now
842    private void parseSQLDIAGSTT() throws DisconnectException, SqlException {
843        if (readFdocaOneByte() == CodePoint.NULLDATA) {
844            return;
845        }
846 
847        // The server should send NULLDATA
848        netAgent_.accumulateChainBreakingReadExceptionAndThrow(
849                new DisconnectException(netAgent_, 
850                    new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
851                    "parseSQLDIAGSTT"));
852    }
853 
854    // SQL Diagnostics Condition Information Array - Identity 0xF5
855    // SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
856    // SQLDCIROW; ROW LID 0xE5; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
857    private NetSqlca[] parseSQLDIAGCI() 
858            throws DisconnectException, SqlException {
859        int num = readFdocaTwoByteLength(); // SQLNUMGRP - SQLNUMROW
860        NetSqlca[] ret_val = null;
861        if (num != 0) {
862            ret_val = new NetSqlca[num];
863        } 
864 
865        for (int i = 0; i < num; i++) {
866            ret_val[i] = parseSQLDCROW();
867        }
868        return ret_val;
869    }
870 
871    // SQL Diagnostics Connection Array - Identity 0xF6
872    // NULLDATA will be received for now
873    private void parseSQLDIAGCN() throws DisconnectException, SqlException {
874        if (readFdocaOneByte() == CodePoint.NULLDATA) {
875            return;
876        }
877        
878        // The server should send NULLDATA
879        netAgent_.accumulateChainBreakingReadExceptionAndThrow(
880                new DisconnectException(netAgent_, 
881                    new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
882                    "parseSQLDIAGCN"));
883    }
884 
885    // SQL Diagnostics Condition Group Description
886    //
887    // SQLDCCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
888    // SQLDCSTATE; PROTOCOL TYPE FCS; ENVLID Ox30; Lengeh Override 5
889    // SQLDCREASON; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
890    // SQLDCLINEN; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
891    // SQLDCROWN; PROTOCOL TYPE I8; ENVLID 0x16; Lengeh Override 8
892    // SQLDCER01; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
893    // SQLDCER02; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
894    // SQLDCER03; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
895    // SQLDCER04; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
896    // SQLDCPART; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
897    // SQLDCPPOP; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
898    // SQLDCMSGID; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 10
899    // SQLDCMDE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
900    // SQLDCPMOD; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
901    // SQLDCRDB; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
902    // SQLDCTOKS; PROTOCOL TYPE N-RLO; ENVLID 0xF7; Length Override 0
903    // SQLDCMSG_m; PROTOCOL TYPE NVMC; ENVLID 0x3F; Length Override 32672
904    // SQLDCMSG_S; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 32672
905    // SQLDCCOLN_m; PROTOCOL TYPE NVCM ; ENVLID 0x3F; Length Override 255
906    // SQLDCCOLN_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
907    // SQLDCCURN_m; PROTOCOL TYPE NVCM; ENVLID 0x3F; Length Override 255
908    // SQLDCCURN_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
909    // SQLDCPNAM_m; PROTOCOL TYPE NVCM; ENVLID 0x3F; Length Override 255
910    // SQLDCPNAM_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
911    // SQLDCXGRP; PROTOCOL TYPE N-GDA; ENVLID 0xD3; Length Override 1
912    private NetSqlca parseSQLDCGRP() 
913            throws DisconnectException, SqlException {
914        
915        int sqldcCode = readFdocaInt(); // SQLCODE
916        String sqldcState = readFdocaString(5, 
917                netAgent_.targetTypdef_.getCcsidSbcEncoding()); // SQLSTATE
918        int sqldcReason = readFdocaInt();  // REASON_CODE
919 
920        skipFdocaBytes(12); // LINE_NUMBER + ROW_NUMBER
921 
922        NetSqlca sqlca = new NetSqlca(netAgent_.netConnection_,
923                    sqldcCode,
924                    sqldcState,
925                    (byte[]) null);
926 
927        skipFdocaBytes(49); // SQLDCER01-04 + SQLDCPART + SQLDCPPOP + SQLDCMSGID
928                            // SQLDCMDE + SQLDCPMOD + RDBNAME
929        parseSQLDCTOKS(); // MESSAGE_TOKENS
930 
931        String sqldcMsg = parseVCS(qrydscTypdef_); // MESSAGE_TEXT
932 
933        if (sqldcMsg != null) {
934            sqlca.setSqlerrmcBytes(sqldcMsg.getBytes(), 
935                    netAgent_.targetTypdef_.getByteOrder());
936        }
937 
938        skipFdocaBytes(12);  // COLUMN_NAME + PARAMETER_NAME + EXTENDED_NAMES
939 
940        parseSQLDCXGRP(); // SQLDCXGRP
941        return sqlca;
942    }
943 
944    // SQL Diagnostics Condition Row - Identity 0xE5
945    // SQLDCGRP; GROUP LID 0xD5; ELEMENT TAKEN 0(all); REP FACTOR 1
946    private NetSqlca parseSQLDCROW() throws DisconnectException, SqlException {
947        return parseSQLDCGRP();
948    }
949    
950    // SQL Diagnostics Condition Token Array - Identity 0xF7
951    // NULLDATA will be received for now
952    void parseSQLDCTOKS() throws DisconnectException, SqlException {
953        if (readFdocaOneByte() == CodePoint.NULLDATA) {
954            return;
955        }
956 
957        // The server should send NULLDATA
958        netAgent_.accumulateChainBreakingReadExceptionAndThrow(
959                new DisconnectException(netAgent_, 
960                    new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
961                    "parseSQLDCTOKS"));
962    }
963 
964    // SQL Diagnostics Extended Names Group Description - Identity 0xD5
965    // NULLDATA will be received for now
966    private void parseSQLDCXGRP() throws DisconnectException, SqlException {
967        if (readFdocaOneByte() == CodePoint.NULLDATA) {
968            return;
969        }
970 
971        // The server should send NULLDATA
972        netAgent_.accumulateChainBreakingReadExceptionAndThrow(
973                new DisconnectException(netAgent_, 
974                    new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
975                    "parseSQLDCXGRP"));
976    }
977 
978    private String parseVCS(Typdef typdefInEffect) throws DisconnectException, SqlException {
979        return readFdocaString(readFdocaTwoByteLength(),
980                typdefInEffect.getCcsidSbcEncoding());
981    }
982 
983    // This is not used for column data.
984    private String readFdocaString(int length, String encoding) throws DisconnectException, SqlException {
985        if (length == 0) {
986            return null;
987        }
988 
989        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
990        // so there is no need to drive a flowFetch (continue query) request for singleton select.
991        if ((position_ + length) > lastValidBytePosition_) {
992            // Check for ENDQRYRM, throw SqlException if already received one.
993            checkAndThrowReceivedEndqryrm();
994 
995            // Send CNTQRY to complete the row/rowset.
996            int lastValidByteBeforeFetch = completeSplitRow();
997 
998            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
999            // throw a SqlException for the ENDQRYRM.
1000            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
1001        }
1002 
1003        String s = null;
1004 
1005        try {
1006            s = new String(dataBuffer_, position_, length, encoding);
1007        } catch (java.io.UnsupportedEncodingException e) {
1008            netAgent_.accumulateChainBreakingReadExceptionAndThrow(
1009                new org.apache.derby.client.am.DisconnectException(
1010                    netAgent_, 
1011                    new ClientMessageId(SQLState.NET_ENCODING_NOT_SUPPORTED), 
1012                    e));
1013        }
1014 
1015        position_ += length;
1016        return s;
1017    }
1018 
1019    void allocateColumnOffsetAndLengthArrays() {
1020        columnDataPosition_ = new int[columns_];
1021        columnDataComputedLength_ = new int[columns_];
1022        isNull_ = new boolean[columns_];
1023    }
1024 
1025    void setBlocking(int queryProtocolType) {
1026        if (queryProtocolType == CodePoint.LMTBLKPRC) {
1027            blocking_ = true;
1028        } else {
1029            blocking_ = false;
1030        }
1031    }
1032 
1033    protected byte[] findExtdtaData(int column) {
1034        byte[] data = null;
1035 
1036        // locate the EXTDTA bytes, if any
1037        Integer key = new Integer(column);
1038 
1039        if (extdtaPositions_.containsKey(key)) {
1040            //  found, get the data
1041            int extdtaQueuePosition = ((Integer) extdtaPositions_.get(key)).intValue();
1042            data = (byte[]) (extdtaData_.get(extdtaQueuePosition));
1043        }
1044 
1045        return data;
1046    }
1047 
1048    public Blob getBlobColumn_(int column, Agent agent) throws SqlException {
1049        int index = column - 1;
1050        int dataOffset;
1051        byte[] data;
1052        Blob blob = null;
1053 
1054        // locate the EXTDTA bytes, if any
1055        data = findExtdtaData(column);
1056 
1057        if (data != null) {
1058            // data found
1059            // set data offset based on the presence of a null indicator
1060            if (!nullable_[index]) {
1061                dataOffset = 0;
1062            } else {
1063                dataOffset = 1;
1064            }
1065 
1066            blob = new Blob(data, agent, dataOffset);
1067        } else {
1068            blob = new Blob(new byte[0], agent, 0);
1069        }
1070 
1071        return blob;
1072    }
1073 
1074 
1075    public Clob getClobColumn_(int column, Agent agent) throws SqlException {
1076        int index = column - 1;
1077        int dataOffset;
1078        byte[] data;
1079        Clob clob = null;
1080 
1081        // locate the EXTDTA bytes, if any
1082        data = findExtdtaData(column);
1083 
1084        if (data != null) {
1085            // data found
1086            // set data offset based on the presence of a null indicator
1087            if (!nullable_[index]) {
1088                dataOffset = 0;
1089            } else {
1090                dataOffset = 1;
1091            }
1092            clob = new Clob(agent, data, charsetName_[index], dataOffset);
1093        } else {
1094            // the locator is not valid, it is a zero-length LOB
1095            clob = new Clob(agent, "");
1096        }
1097 
1098        return clob;
1099    }
1100 
1101    public byte[] getClobBytes_(int column, int[] dataOffset /*output*/) throws SqlException {
1102        int index = column - 1;
1103        byte[] data = null;
1104 
1105        // locate the EXTDTA bytes, if any
1106        data = findExtdtaData(column);
1107 
1108        if (data != null) {
1109            // data found
1110            // set data offset based on the presence of a null indicator
1111            if (!nullable_[index]) {
1112                dataOffset[0] = 0;
1113            } else {
1114                dataOffset[0] = 1;
1115            }
1116        }
1117 
1118        return data;
1119    }
1120 
1121    // this is really an event-callback from NetStatementReply.parseSQLDTARDarray()
1122    void initializeColumnInfoArrays(Typdef typdef,
1123                                    int columnCount, int targetSqlamForTypdef) throws DisconnectException {
1124        qrydscTypdef_ = typdef;
1125 
1126        // Allocate  arrays to hold the descriptor information.
1127        setNumberOfColumns(columnCount);
1128        fdocaLength_ = new int[columnCount];
1129        isGraphic_ = new boolean[columnCount];
1130        typeToUseForComputingDataLength_ = new int[columnCount];
1131        targetSqlamForTypdef_ = targetSqlamForTypdef;
1132    }
1133 
1134 
1135    int ensureSpaceForDataBuffer(int ddmLength) {
1136        if (dataBuffer_ == null) {
1137            allocateDataBuffer();
1138        }
1139        //super.resultSet.cursor.clearColumnDataOffsetsCache();
1140        // Need to know how many bytes to ask from the Reply object,
1141        // and handle the case where buffer is not big enough for all the bytes.
1142        // Get the length in front of the code point first.
1143 
1144        int bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
1145 
1146        // Make sure the buffer has at least ddmLength amount of room left.
1147        // If not, expand the buffer before calling the getQrydtaData() method.
1148        if (bytesAvailableInDataBuffer < ddmLength) {
1149 
1150            // Get a new buffer that is twice the size of the current buffer.
1151            // Copy the contents from the old buffer to the new buffer.
1152            int newBufferSize = 2 * dataBuffer_.length;
1153 
1154            while (newBufferSize < ddmLength) {
1155                newBufferSize = 2 * newBufferSize;
1156            }
1157 
1158            byte[] tempBuffer = new byte[newBufferSize];
1159 
1160            System.arraycopy(dataBuffer_,
1161                    0,
1162                    tempBuffer,
1163                    0,
1164                    lastValidBytePosition_);
1165 
1166            // Make the new buffer the dataBuffer.
1167            dataBuffer_ = tempBuffer;
1168 
1169            // Recalculate bytesAvailableInDataBuffer
1170            bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
1171        }
1172        return bytesAvailableInDataBuffer;
1173    }
1174 
1175    protected void getMoreData_() throws SqlException {
1176        // reset the dataBuffer_ before getting more data if cursor is foward-only.
1177        // getMoreData() is only called in Cursor.next() when current position is
1178        // equal to lastValidBytePosition_.
1179        if (netResultSet_.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) {
1180            resetDataBuffer();
1181        }
1182        netResultSet_.flowFetch();
1183    }
1184 
1185    public void nullDataForGC()       // memory leak fix
1186    {
1187        super.nullDataForGC();
1188        qrydscTypdef_ = null;
1189        typeToUseForComputingDataLength_ = null;
1190        isGraphic_ = null;
1191 
1192        if (extdtaPositions_ != null) {
1193            extdtaPositions_.clear();
1194        }
1195        extdtaPositions_ = null;
1196 
1197        if (extdtaData_ != null) {
1198            extdtaData_.clear();
1199        }
1200        extdtaData_ = null;
1201    }
1202 
1203    // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD.
1204    // This means some error has occurred on the server and the server is terminating the query.
1205    // Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already
1206    // been received.  If so, do not send CNTQRY because the cursor is already closed on the server.
1207    // Instead, throw a SqlException.  Since we did not receive a complete row, it is not safe to
1208    // allow the application to continue to access the ResultSet, so we close it.
1209    private void checkAndThrowReceivedEndqryrm() throws SqlException {
1210        // If we are in a split row, and before sending CNTQRY, check whether an ENDQRYRM
1211        // has been received.
1212        if (!netResultSet_.openOnServer_) {
1213            SqlException sqlException = null;
1214            int sqlcode = org.apache.derby.client.am.Utils.getSqlcodeFromSqlca(netResultSet_.queryTerminatingSqlca_);
1215            if (sqlcode < 0) {
1216                sqlException = new SqlException(agent_.logWriter_, netResultSet_.queryTerminatingSqlca_);
1217            } else {
1218                sqlException = new SqlException(agent_.logWriter_, 
1219                    new ClientMessageId(SQLState.NET_QUERY_PROCESSING_TERMINATED));
1220            }
1221            try {
1222                netResultSet_.closeX(); // the auto commit logic is in closeX()
1223            } catch (SqlException e) {
1224                sqlException.setNextException(e);
1225            }
1226            throw sqlException;
1227        }
1228    }
1229 
1230    private void checkAndThrowReceivedEndqryrm(int lastValidBytePositionBeforeFetch) throws SqlException {
1231        // if we have received more data in the dataBuffer_, just return.
1232        if (lastValidBytePosition_ > lastValidBytePositionBeforeFetch) {
1233            return;
1234        }
1235        checkAndThrowReceivedEndqryrm();
1236    }
1237 
1238    private int completeSplitRow() throws DisconnectException, SqlException {
1239        int lastValidBytePositionBeforeFetch = 0;
1240        if (netResultSet_ != null && netResultSet_.scrollable_) {
1241            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1242            netResultSet_.flowFetchToCompleteRowset();
1243        } else {
1244            // Shift partial row to the beginning of the dataBuffer
1245            shiftPartialRowToBeginning();
1246            resetCurrentRowPosition();
1247            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1248            netResultSet_.flowFetch();
1249        }
1250        return lastValidBytePositionBeforeFetch;
1251    }
1252 
1253    private int completeSplitRow(int index) throws DisconnectException, SqlException {
1254        int lastValidBytePositionBeforeFetch = 0;
1255        if (netResultSet_ != null && netResultSet_.scrollable_) {
1256            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1257            netResultSet_.flowFetchToCompleteRowset();
1258        } else {
1259            // Shift partial row to the beginning of the dataBuffer
1260            shiftPartialRowToBeginning();
1261            adjustColumnOffsetsForColumnsPreviouslyCalculated(index);
1262            resetCurrentRowPosition();
1263            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1264            netResultSet_.flowFetch();
1265        }
1266        return lastValidBytePositionBeforeFetch;
1267    }
1268 
1269    private int[] allocateColumnDataPositionArray(int row) {
1270        int[] columnDataPosition;
1271        if (columnDataPositionCache_.size() == row) {
1272            columnDataPosition = new int[columns_];
1273            columnDataPositionCache_.add(columnDataPosition);
1274        } else {
1275            columnDataPosition = (int[]) columnDataPositionCache_.get(row);
1276        }
1277        return columnDataPosition;
1278    }
1279 
1280    private int[] allocateColumnDataComputedLengthArray(int row) {
1281        int[] columnDataComputedLength;
1282        if (columnDataLengthCache_.size() == row) {
1283            columnDataComputedLength = new int[columns_];
1284            columnDataLengthCache_.add(columnDataComputedLength);
1285        } else {
1286            columnDataComputedLength = (int[]) columnDataLengthCache_.get(row);
1287        }
1288        return columnDataComputedLength;
1289    }
1290 
1291    private boolean[] allocateColumnDataIsNullArray(int row) {
1292        boolean[] columnDataIsNull;
1293        if (columnDataIsNullCache_.size() <= row) {
1294            columnDataIsNull = new boolean[columns_];
1295            columnDataIsNullCache_.add(columnDataIsNull);
1296        } else {
1297            columnDataIsNull = (boolean[]) columnDataIsNullCache_.get(row);
1298        }
1299        return columnDataIsNull;
1300    }
1301 
1302    protected int getDecimalLength(int index) {
1303        return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2;
1304    }
1305 
1306    /**
1307     * Set the value of value of allRowsReceivedFromServer_.
1308     *
1309     * @param b a <code>boolean</code> value indicating whether all
1310     * rows are received from the server
1311     */
1312    public final void setAllRowsReceivedFromServer(boolean b) {
1313        if (b && qryclsimpEnabled_) {
1314            netResultSet_.markClosedOnServer();
1315        }
1316        super.setAllRowsReceivedFromServer(b);
1317    }
1318 
1319    /**
1320     * Set a flag indicating whether QRYCLSIMP is enabled.
1321     *
1322     * @param flag true if QRYCLSIMP is enabled
1323     */
1324    final void setQryclsimpEnabled(boolean flag) {
1325        qryclsimpEnabled_ = flag;
1326    }
1327 
1328    /**
1329     * Check whether QRYCLSIMP is enabled on this cursor.
1330     *
1331     * @return true if QRYCLSIMP is enabled
1332     */
1333    final boolean getQryclsimpEnabled() {
1334        return qryclsimpEnabled_;
1335    }
1336}

[all classes][org.apache.derby.client.net]
EMMA 2.0.5312 (C) Vladimir Roubtsov