KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > client > net > NetCursor


1 /*
2
3    Derby - Class org.apache.derby.client.net.NetCursor
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to You under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20 */

21
22 package org.apache.derby.client.net;
23
24 import org.apache.derby.client.am.Agent;
25 import org.apache.derby.client.am.Blob;
26 import org.apache.derby.client.am.Clob;
27 import org.apache.derby.client.am.DisconnectException;
28 import org.apache.derby.client.am.SignedBinary;
29 import org.apache.derby.client.am.SqlException;
30 import org.apache.derby.client.am.ClientMessageId;
31 import org.apache.derby.client.am.SqlWarning;
32 import org.apache.derby.client.am.Types;
33 import org.apache.derby.client.am.SqlCode;
34 import org.apache.derby.shared.common.reference.SQLState;
35 import org.apache.derby.shared.common.sanity.SanityManager;
36
37 public class NetCursor extends org.apache.derby.client.am.Cursor {
38
39     NetResultSet netResultSet_;
40     NetAgent netAgent_;
41
42     Typdef qrydscTypdef_;
43
44     int targetSqlamForTypdef_;
45
46
47     // override column meta data
48
int numMddOverrides_;
49     int maximumRowSize_;
50     boolean blocking_; // if true, multiple rows may be "blocked" in a single reply
51

52     // Raw fdoca column meta data.
53
int[] typeToUseForComputingDataLength_;
54     boolean[] isGraphic_;
55
56     // key = column position, value = index into extdtaData_
57
java.util.HashMap JavaDoc extdtaPositions_;
58     java.util.ArrayList JavaDoc extdtaData_; // queue to hold EXTDTA data that hasn't been correlated to its column #
59

60
61     boolean rtnextrow_ = true;
62
63     /** Flag indicating whether the result set on the server is
64      * implicitly closed when end-of-data is received. */

65     private boolean qryclsimpEnabled_;
66
67     //-----------------------------constants--------------------------------------
68

69     //---------------------constructors/finalizer---------------------------------
70

71     NetCursor(NetAgent netAgent) {
72         super(netAgent);
73         netAgent_ = netAgent;
74         numMddOverrides_ = 0;
75         maximumRowSize_ = 0;
76         extdtaPositions_ = new java.util.HashMap JavaDoc();
77         extdtaData_ = new java.util.ArrayList JavaDoc();
78     }
79
80     NetCursor(NetAgent netAgent,
81               int qryprctyp) //protocolType, CodePoint.FIXROWPRC | CodePoint.LMTBLKPRC
82
{
83         this(netAgent);
84         if (qryprctyp == CodePoint.FIXROWPRC) {
85             blocking_ = false;
86         } else if (qryprctyp == CodePoint.LMTBLKPRC) {
87             blocking_ = true;
88         }
89     }
90     //-----------------------------parsing the data buffer------------------------
91

92     /**
93      * Calculate the column offsets for a row.
94      * <p>
95      * Pseudo-code:
96      * <ol>
97      * <li>parse thru the current row in dataBuffer computing column
98      * offsets</li>
99      * <li>if (we hit the super.lastValidBytePosition, ie. encounter
100      * partial row)
101      * <ol>
102      * <li>shift partial row bytes to beginning of dataBuffer
103      * (this.shiftPartialRowToBeginning())</li>
104      * <li>reset current row position (also done by
105      * this.shiftPartialRowToBeginning())</li>
106      * <li>send and recv continue-query into commBuffer
107      * (rs.flowContinueQuery())</li>
108      * <li>parse commBuffer up to QRYDTA
109      * (rs.flowContinueQuery())</li>
110      * <li>copy query data from reply's commBuffer to our
111      * dataBuffer (this.copyQrydta())</li>
112      * </ol>
113      * </ol>
114      *
115      * @param rowIndex row index
116      * @param allowServerFetch if true, allow fetching more data from
117      * server
118      * @return <code>true</code> if the current row position is a
119      * valid row position.
120      * @exception SqlException
121      * @exception DisconnectException
122      */

123     protected
124         boolean calculateColumnOffsetsForRow_(int rowIndex,
125                                               boolean allowServerFetch)
126         throws SqlException, DisconnectException
127     {
128         int daNullIndicator = CodePoint.NULLDATA;
129         int colNullIndicator = CodePoint.NULLDATA;
130         int length;
131
132         int[] columnDataPosition = null;
133         int[] columnDataComputedLength = null;
134         boolean[] columnDataIsNull = null;
135         boolean receivedDeleteHoleWarning = false;
136         boolean receivedRowUpdatedWarning = false;
137
138         if ((position_ == lastValidBytePosition_) &&
139                 (netResultSet_ != null) && (netResultSet_.scrollable_)) {
140             return false;
141         }
142
143         if (hasLobs_) {
144             extdtaPositions_.clear(); // reset positions for this row
145
}
146
147         NetSqlca[] netSqlca = this.parseSQLCARD(qrydscTypdef_);
148
149         if (netSqlca != null) {
150             for (int i=0;i<netSqlca.length; i++) {
151                 int sqlcode = netSqlca[i].getSqlCode();
152                 if (sqlcode < 0) {
153                     throw new SqlException(netAgent_.logWriter_,
154                             netSqlca[i]);
155                 } else {
156                     if (sqlcode == SqlCode.END_OF_DATA.getCode()) {
157                         setAllRowsReceivedFromServer(true);
158                         if (netResultSet_ != null &&
159                                 netSqlca[i].containsSqlcax()) {
160                             netResultSet_.setRowCountEvent(
161                                     netSqlca[i].getRowCount(
162                                         qrydscTypdef_));
163                         }
164                     } else if (netResultSet_ != null && sqlcode > 0) {
165                         String JavaDoc sqlState = netSqlca[i].getSqlState();
166                         if (!sqlState.equals(SQLState.ROW_DELETED) &&
167                                 !sqlState.equals(SQLState.ROW_UPDATED)) {
168                             netResultSet_.accumulateWarning(
169                                     new SqlWarning(agent_.logWriter_,
170                                         netSqlca[i]));
171                         } else {
172                             receivedDeleteHoleWarning
173                                     |= sqlState.equals(SQLState.ROW_DELETED);
174                             receivedRowUpdatedWarning
175                                     |= sqlState.equals(SQLState.ROW_UPDATED);
176                         }
177                     }
178                 }
179             }
180         }
181
182         setIsUpdataDeleteHole(rowIndex, receivedDeleteHoleWarning);
183         setIsRowUpdated(receivedRowUpdatedWarning);
184         
185         // If we don't have at least one byte in the buffer for the DA null indicator,
186
// then we need to send a CNTQRY request to fetch the next block of data.
187
// Read the DA null indicator.
188
daNullIndicator = readFdocaOneByte();
189
190         // In the case for held cursors, the +100 comes back as part of the QRYDTA, and as
191
// we are parsing through the row that contains the SQLCA with +100, we mark the
192
// nextRowPosition_ which is the lastValidBytePosition_, but we don't mark the
193
// currentRowPosition_ until the next time next() is called causing the check
194
// cursor_.currentRowPositionIsEqualToNextRowPosition () to fail in getRow() and thus
195
// not returning 0 when it should. So we need to mark the current row position immediately
196
// in order for getRow() to be able to pick it up.
197

198         // markNextRowPosition() is called again once this method returns, but it is ok
199
// since it's only resetting nextRowPosition_ to position_ and position_ will
200
// not change again from this point.
201

202         if (allRowsReceivedFromServer() &&
203             (position_ == lastValidBytePosition_)) {
204             markNextRowPosition();
205             makeNextRowPositionCurrent();
206             return false;
207         }
208
209         // If data flows....
210
if (daNullIndicator == 0x0) {
211
212         if (SanityManager.DEBUG && receivedDeleteHoleWarning) {
213         SanityManager.THROWASSERT("Delete hole warning received: nulldata expected");
214         }
215             incrementRowsReadEvent();
216
217             // netResultSet_ is null if this method is invoked from Lob.position()
218
// If row has exceeded the size of the ArrayList, new up a new int[] and add it to the
219
// ArrayList, otherwise just reuse the int[].
220
if (netResultSet_ != null && netResultSet_.scrollable_) {
221                 columnDataPosition = allocateColumnDataPositionArray(rowIndex);
222                 columnDataComputedLength = allocateColumnDataComputedLengthArray(rowIndex);
223                 columnDataIsNull = allocateColumnDataIsNullArray(rowIndex);
224                 // Since we are no longer setting the int[]'s to null for a delete/update hole, we need
225
// another way of keeping track of the delete/update holes.
226
setIsUpdataDeleteHole(rowIndex, false);
227             } else {
228                 // Use the arrays defined on the Cursor for forward-only cursors.
229
// can they ever be null
230
if (columnDataPosition_ == null || columnDataComputedLength_ == null || isNull_ == null) {
231                     allocateColumnOffsetAndLengthArrays();
232                 }
233                 columnDataPosition = columnDataPosition_;
234                 columnDataComputedLength = columnDataComputedLength_;
235                 columnDataIsNull = isNull_;
236             }
237
238             // Loop through the columns
239
for (int index = 0; index < columns_; index++) {
240                 // If column is nullable, read the 1-byte null indicator.
241
if (nullable_[index])
242                 // Need to pass the column index so all previously calculated offsets can be
243
// readjusted if the query block splits on a column null indicator.
244

245                 // null indicators from FD:OCA data
246
// 0 to 127: a data value will flow.
247
// -1 to -128: no data value will flow.
248
{
249                     colNullIndicator = readFdocaOneByte(index);
250                 }
251
252                 // If non-null column data
253
if (!nullable_[index] || (colNullIndicator >= 0 && colNullIndicator <= 127)) {
254
255                     // Set the isNull indicator to false
256
columnDataIsNull[index] = false;
257
258                     switch (typeToUseForComputingDataLength_[index]) {
259                     // for fixed length data
260
case Typdef.FIXEDLENGTH:
261                         columnDataPosition[index] = position_;
262                         if (isGraphic_[index]) {
263                             columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
264                         } else {
265                             columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
266                         }
267                         break;
268
269                         // for variable character string and variable byte string,
270
// there are 2-byte of length in front of the data
271
case Typdef.TWOBYTELENGTH:
272                         columnDataPosition[index] = position_;
273                         length = readFdocaTwoByteLength(index);
274                         // skip length + the 2-byte length field
275
if (isGraphic_[index]) {
276                             columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 2;
277                         } else {
278                             columnDataComputedLength[index] = skipFdocaBytes(length, index) + 2;
279                         }
280                         break;
281
282                         // For decimal columns, determine the precision, scale, and the representation
283
case Typdef.DECIMALLENGTH:
284                         columnDataPosition[index] = position_;
285                         columnDataComputedLength[index] = skipFdocaBytes(getDecimalLength(index), index);
286                         break;
287
288                     case Typdef.LOBLENGTH:
289                         columnDataPosition[index] = position_;
290                         columnDataComputedLength[index] = this.skipFdocaBytes(fdocaLength_[index] & 0x7fff, index);
291                         break;
292
293                         // for short variable character string and short variable byte string,
294
// there is a 1-byte length in front of the data
295
case Typdef.ONEBYTELENGTH:
296                         columnDataPosition[index] = position_;
297                         length = readFdocaOneByte(index);
298                         // skip length + the 1-byte length field
299
if (isGraphic_[index]) {
300                             columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 1;
301                         } else {
302                             columnDataComputedLength[index] = skipFdocaBytes(length, index) + 1;
303                         }
304                         break;
305
306                     default:
307                         columnDataPosition[index] = position_;
308                         if (isGraphic_[index]) {
309                             columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
310                         } else {
311                             columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
312                         }
313                         break;
314                     }
315                 } else if ((colNullIndicator & 0x80) == 0x80) {
316                     // Null data. Set the isNull indicator to true.
317
columnDataIsNull[index] = true;
318                 }
319             }
320
321             // set column offsets for the current row.
322
columnDataPosition_ = columnDataPosition;
323             columnDataComputedLength_ = columnDataComputedLength;
324             isNull_ = columnDataIsNull;
325
326             if (!allRowsReceivedFromServer()) {
327                 calculateLobColumnPositionsForRow();
328                 // Flow another CNTQRY if we are blocking, are using rtnextrow, and expect
329
// non-trivial EXTDTAs for forward only cursors. Note we do not support
330
// EXTDTA retrieval for scrollable cursors.
331
// if qryrowset was sent on excsqlstt for a sp call, which is only the case
332
if (blocking_ && rtnextrow_ &&
333                     !netResultSet_.scrollable_ &&
334                     !extdtaPositions_.isEmpty()) {
335                     if (allowServerFetch) {
336                         netResultSet_.flowFetch();
337                     } else {
338                         return false;
339                     }
340                 }
341             }
342         } else {
343             if (netResultSet_ != null && netResultSet_.scrollable_) {
344         if (receivedDeleteHoleWarning) {
345             setIsUpdataDeleteHole(rowIndex, true);
346         } else {
347             if (SanityManager.DEBUG) {
348             // Invariant: for SUR, we introduced the warning
349
// in addition to null data.
350
SanityManager
351                 .THROWASSERT("Delete hole warning expected");
352             }
353         }
354             }
355         }
356
357         // If blocking protocol is used, we could have already received an ENDQRYRM,
358
// which sets allRowsReceivedFromServer_ to true. It's safe to assume that all of
359
// our QRYDTA's have been successfully copied to the dataBuffer. And even though
360
// the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through
361
// the data in the dataBuffer.
362
// But in the case where fixed row protocol is used,
363
if (!blocking_ && allRowsReceivedFromServer() &&
364             daNullIndicator == 0xFF) {
365             return false;
366         } else {
367             return true;
368         }
369     }
370
371     /**
372      * Scan the data buffer to see if end of data (SQL state 02000)
373      * has been received. This method should only be called when the
374      * cursor is being closed since the pointer to the current row can
375      * be modified.
376      *
377      * @exception SqlException
378      */

379     void scanDataBufferForEndOfData() throws SqlException {
380         while (!allRowsReceivedFromServer() &&
381                (position_ != lastValidBytePosition_)) {
382             stepNext(false);
383         }
384     }
385
386     protected boolean isDataBufferNull() {
387         if (dataBuffer_ == null) {
388             return true;
389         } else {
390             return false;
391         }
392     }
393
394     protected void allocateDataBuffer() {
395         int length;
396         if (maximumRowSize_ > DssConstants.MAX_DSS_LEN) {
397             length = maximumRowSize_;
398         } else {
399             length = DssConstants.MAX_DSS_LEN;
400         }
401
402         dataBuffer_ = new byte[length];
403         position_ = 0;
404         lastValidBytePosition_ = 0;
405     }
406
407     protected void allocateDataBuffer(int length) {
408         dataBuffer_ = new byte[length];
409     }
410
411
412     private int readFdocaInt() throws org.apache.derby.client.am.DisconnectException, SqlException {
413         if ((position_ + 4) > lastValidBytePosition_) {
414             // Check for ENDQRYRM, throw SqlException if already received one.
415
checkAndThrowReceivedEndqryrm();
416
417             // Send CNTQRY to complete the row/rowset.
418
int lastValidByteBeforeFetch = completeSplitRow();
419
420             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
421
// throw a SqlException for the ENDQRYRM.
422
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
423         }
424
425         int i = SignedBinary.getInt(dataBuffer_, position_);
426         position_ += 4;
427         return i;
428     }
429
430     // Reads 8-bytes from the dataBuffer from the current position.
431
// If position is already at the end of the buffer, send CNTQRY to get more
432
// data.
433
private long readFdocaLong() throws
434             org.apache.derby.client.am.DisconnectException, SqlException {
435         if ((position_ + 8) > lastValidBytePosition_) {
436             // Check for ENDQRYRM, throw SqlException if already received one.
437
checkAndThrowReceivedEndqryrm();
438
439             // Send CNTQRY to complete the row/rowset.
440
int lastValidByteBeforeFetch = completeSplitRow();
441
442             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was
443
// received, throw a SqlException for the ENDQRYRM.
444
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
445         }
446
447         long i = SignedBinary.getLong(dataBuffer_, position_);
448         position_ += 8;
449         return i;
450     }
451         
452     // Reads 1-byte from the dataBuffer from the current position.
453
// If position is already at the end of the buffer, send CNTQRY to get more data.
454
private int readFdocaOneByte() throws org.apache.derby.client.am.DisconnectException, SqlException {
455         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
456
// so there is no need to drive a flowFetch (continue query) request for singleton select.
457
if (position_ == lastValidBytePosition_) {
458             // Check for ENDQRYRM, throw SqlException if already received one.
459
checkAndThrowReceivedEndqryrm();
460
461             // Send CNTQRY to complete the row/rowset.
462
int lastValidByteBeforeFetch = completeSplitRow();
463
464             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
465
// throw a SqlException for the ENDQRYRM.
466
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
467         }
468         return dataBuffer_[position_++] & 0xff;
469     }
470
471     // Reads 1-byte from the dataBuffer from the current position.
472
// If position is already at the end of the buffer, send CNTQRY to get more data.
473
private int readFdocaOneByte(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
474         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
475
// so there is no need to drive a flowFetch (continue query) request for singleton select.
476
if (position_ == lastValidBytePosition_) {
477             // Check for ENDQRYRM, throw SqlException if already received one.
478
checkAndThrowReceivedEndqryrm();
479
480             // Send CNTQRY to complete the row/rowset.
481
int lastValidByteBeforeFetch = completeSplitRow(index);
482
483             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
484
// throw a SqlException for the ENDQRYRM.
485
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
486         }
487         return dataBuffer_[position_++] & 0xff;
488     }
489
490     // Reads <i>length</i> number of bytes from the dataBuffer starting from the
491
// current position. Returns a new byte array which contains the bytes read.
492
// If current position plus length goes past the lastValidBytePosition, send
493
// CNTQRY to get more data.
494
private byte[] readFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
495         byte[] b = new byte[length];
496         ;
497
498         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
499
// so there is no need to drive a flowFetch (continue query) request for singleton select.
500
if ((position_ + length) > lastValidBytePosition_) {
501             // Check for ENDQRYRM, throw SqlException if already received one.
502
checkAndThrowReceivedEndqryrm();
503
504             // Send CNTQRY to complete the row/rowset.
505
int lastValidByteBeforeFetch = completeSplitRow();
506
507             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
508
// throw a SqlException for the ENDQRYRM.
509
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
510         }
511
512         for (int i = 0; i < length; i++) {
513             b[i] = dataBuffer_[position_++];
514         }
515
516         return b;
517     }
518
519     // Reads 2-bytes from the dataBuffer starting from the current position, and
520
// returns an integer constructed from the 2-bytes. If current position plus
521
// 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data.
522
private int readFdocaTwoByteLength() throws org.apache.derby.client.am.DisconnectException, SqlException {
523         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
524
// so there is no need to drive a flowFetch (continue query) request for singleton select.
525
if ((position_ + 2) > lastValidBytePosition_) {
526             // Check for ENDQRYRM, throw SqlException if already received one.
527
checkAndThrowReceivedEndqryrm();
528
529             // Send CNTQRY to complete the row/rowset.
530
int lastValidByteBeforeFetch = completeSplitRow();
531
532             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
533
// throw a SqlException for the ENDQRYRM.
534
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
535         }
536
537         return
538                 ((dataBuffer_[position_++] & 0xff) << 8) +
539                 ((dataBuffer_[position_++] & 0xff) << 0);
540     }
541
542     private int readFdocaTwoByteLength(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
543         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
544
// so there is no need to drive a flowFetch (continue query) request for singleton select.
545
if ((position_ + 2) > lastValidBytePosition_) {
546             // Check for ENDQRYRM, throw SqlException if already received one.
547
checkAndThrowReceivedEndqryrm();
548
549             // Send CNTQRY to complete the row/rowset.
550
int lastValidByteBeforeFetch = completeSplitRow(index);
551
552             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
553
// throw a SqlException for the ENDQRYRM.
554
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
555         }
556
557         return
558                 ((dataBuffer_[position_++] & 0xff) << 8) +
559                 ((dataBuffer_[position_++] & 0xff) << 0);
560     }
561
562     // Check if position plus length goes past the lastValidBytePosition.
563
// If so, send CNTQRY to get more data.
564
// length - number of bytes to skip
565
// returns the number of bytes skipped
566
private int skipFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
567         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
568
// so there is no need to drive a flowFetch (continue query) request for singleton select.
569
if ((position_ + length) > lastValidBytePosition_) {
570             // Check for ENDQRYRM, throw SqlException if already received one.
571
checkAndThrowReceivedEndqryrm();
572
573             // Send CNTQRY to complete the row/rowset.
574
int lastValidByteBeforeFetch = completeSplitRow();
575
576             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
577
// throw a SqlException for the ENDQRYRM.
578
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
579         }
580         position_ += length;
581         return length;
582     }
583
584     private int skipFdocaBytes(int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
585         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
586
// so there is no need to drive a flowFetch (continue query) request for singleton select.
587
if ((position_ + length) > lastValidBytePosition_) {
588             // Check for ENDQRYRM, throw SqlException if already received one.
589
checkAndThrowReceivedEndqryrm();
590
591             // Send CNTQRY to complete the row/rowset.
592
int lastValidByteBeforeFetch = completeSplitRow(index);
593
594             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
595
// throw a SqlException for the ENDQRYRM.
596
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
597         }
598
599         position_ += length;
600         return length;
601     }
602
603     // Shift partial row bytes to beginning of dataBuffer,
604
// and resets current row position, and lastValidBytePosition.
605
// When we shift partial row, we'll have to recalculate column offsets
606
// up to this column.
607
private void shiftPartialRowToBeginning() {
608         // Get the length to shift from the beginning of the partial row.
609
int length = lastValidBytePosition_ - currentRowPosition_;
610
611         // shift the data in the dataBufferStream
612
dataBufferStream_.reset();
613         if (dataBuffer_ != null) {
614             dataBufferStream_.write(dataBuffer_, currentRowPosition_, length);
615         }
616
617         for (int i = 0; i < length; i++) {
618             dataBuffer_[i] = dataBuffer_[currentRowPosition_ + i];
619         }
620
621         position_ = length - (lastValidBytePosition_ - position_);
622         lastValidBytePosition_ = length;
623     }
624
625     private void adjustColumnOffsetsForColumnsPreviouslyCalculated(int index) {
626         for (int j = 0; j <= index; j++) {
627             columnDataPosition_[j] -= currentRowPosition_;
628         }
629     }
630
631     private void resetCurrentRowPosition() {
632         currentRowPosition_ = 0;
633     }
634
635     // Calculates the column index for Lob objects constructed from EXTDTA data.
636
// Describe information isn't sufficient because we have to check
637
// for trivial values (nulls or zero-length) and exclude them.
638
void calculateLobColumnPositionsForRow() {
639         int currentPosition = 0;
640
641         for (int i = 0; i < columns_; i++) {
642             if (isNonTrivialDataLob(i))
643             // key = column position, data = index to corresponding data in extdtaData_
644
// ASSERT: the server always returns the EXTDTA objects in ascending order
645
{
646                 extdtaPositions_.put(new Integer JavaDoc(i + 1), new Integer JavaDoc(currentPosition++));
647             }
648         }
649     }
650
651     // prereq: the base data for the cursor has been processed for offsets and lengths
652
boolean isNonTrivialDataLob(int index) {
653         long length = 0L;
654
655         if (isNull_[index] ||
656                 (jdbcTypes_[index] != Types.BLOB &&
657                 jdbcTypes_[index] != Types.CLOB)) {
658             return false;
659         }
660
661         int position = columnDataPosition_[index];
662
663         // if the high-order bit is set, length is unknown -> set value to x'FF..FF'
664
if (((dataBuffer_[position]) & 0x80) == 0x80) {
665             length = -1;
666         } else {
667
668             byte[] lengthBytes = new byte[columnDataComputedLength_[index]];
669             byte[] longBytes = new byte[8];
670
671             System.arraycopy(dataBuffer_,
672                     position,
673                     lengthBytes,
674                     0,
675                     columnDataComputedLength_[index]);
676
677             // right-justify for BIG ENDIAN
678
int j = 0;
679             for (int i = 8 - columnDataComputedLength_[index]; i < 8; i++) {
680                 longBytes[i] = lengthBytes[j];
681                 j++;
682             }
683             length = SignedBinary.getLong(longBytes, 0);
684         }
685         return (length != 0L) ? true : false;
686     }
687
688     protected void clearLobData_() {
689         extdtaData_.clear();
690         extdtaPositions_.clear();
691     }
692
693     // SQLCARD : FDOCA EARLY ROW
694
// SQL Communications Area Row Description
695
//
696
// FORMAT FOR ALL SQLAM LEVELS
697
// SQLCAGRP; GROUP LID 0x54; ELEMENT TAKEN 0(all); REP FACTOR 1
698
NetSqlca[] parseSQLCARD(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
699         return parseSQLCAGRP(typdef);
700     }
701
702     // SQLCAGRP : FDOCA EARLY GROUP
703
// SQL Communcations Area Group Description
704
//
705
// FORMAT FOR SQLAM <= 6
706
// SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
707
// SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
708
// SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
709
// SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
710
//
711
// FORMAT FOR SQLAM >= 7
712
// SQLCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
713
// SQLSTATE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
714
// SQLERRPROC; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
715
// SQLCAXGRP; PROTOCOL TYPE N-GDA; ENVLID 0x52; Length Override 0
716
// SQLDIAGGRP; PROTOCOL TYPE N-GDA; ENVLID 0x56; Length Override 0
717
private NetSqlca[] parseSQLCAGRP(Typdef typdef) throws org.apache.derby.client.am.DisconnectException, SqlException {
718         if (readFdocaOneByte() == CodePoint.NULLDATA) {
719             return null;
720         }
721         int sqlcode = readFdocaInt();
722         byte[] sqlstate = readFdocaBytes(5);
723         byte[] sqlerrproc = readFdocaBytes(8);
724         NetSqlca netSqlca = new NetSqlca(netAgent_.netConnection_, sqlcode, sqlstate, sqlerrproc);
725
726         parseSQLCAXGRP(typdef, netSqlca);
727
728         NetSqlca[] sqlCa = parseSQLDIAGGRP();
729
730         NetSqlca[] ret_val;
731         if (sqlCa != null) {
732             ret_val = new NetSqlca[sqlCa.length + 1];
733             System.arraycopy(sqlCa, 0, ret_val, 1, sqlCa.length);
734         } else {
735             ret_val = new NetSqlca[1];
736         }
737         ret_val[0] = netSqlca;
738         
739         return ret_val;
740     }
741
742     // SQLCAXGRP : EARLY FDOCA GROUP
743
// SQL Communications Area Exceptions Group Description
744
//
745
// FORMAT FOR SQLAM <= 6
746
// SQLRDBNME; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 18
747
// SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
748
// SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
749
// SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
750
// SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
751
// SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
752
// SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
753
// SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
754
// SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
755
// SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
756
// SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
757
// SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
758
// SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
759
// SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
760
// SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
761
// SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
762
// SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
763
// SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
764
// SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
765
// SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
766
//
767
// FORMAT FOR SQLAM >= 7
768
// SQLERRD1; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
769
// SQLERRD2; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
770
// SQLERRD3; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
771
// SQLERRD4; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
772
// SQLERRD5; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
773
// SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
774
// SQLWARN0; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
775
// SQLWARN1; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
776
// SQLWARN2; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
777
// SQLWARN3; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
778
// SQLWARN4; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
779
// SQLWARN5; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
780
// SQLWARN6; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
781
// SQLWARN7; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
782
// SQLWARN8; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
783
// SQLWARN9; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
784
// SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
785
// SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
786
// SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
787
// SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
788
private void parseSQLCAXGRP(Typdef typdef, NetSqlca netSqlca) throws DisconnectException, SqlException {
789         if (readFdocaOneByte() == CodePoint.NULLDATA) {
790             netSqlca.setContainsSqlcax(false);
791             return;
792         }
793
794
795         // SQLERRD1 to SQLERRD6; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
796
int[] sqlerrd = new int[6];
797         for (int i = 0; i < sqlerrd.length; i++) {
798             sqlerrd[i] = readFdocaInt();
799         }
800
801         // SQLWARN0 to SQLWARNA; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 1
802
byte[] sqlwarn = readFdocaBytes(11);
803
804         // skip over the rdbnam for now
805
// SQLRDBNAME; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
806
parseVCS(typdef);
807
808         // SQLERRMSG_m; PROTOCOL TYPE VCM; ENVLID 0x3E; Length Override 70
809
// SQLERRMSG_s; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 70
810
int varcharLength = readFdocaTwoByteLength(); // mixed length
811
byte[] sqlerrmc = null;
812         int sqlerrmcCcsid = 0;
813         if (varcharLength != 0) { // if mixed
814
sqlerrmc = readFdocaBytes(varcharLength); // read mixed bytes
815
sqlerrmcCcsid = typdef.getCcsidMbc();
816             skipFdocaBytes(2); // skip single length
817
} else {
818             varcharLength = readFdocaTwoByteLength(); // read single length
819
sqlerrmc = readFdocaBytes(varcharLength); // read single bytes
820
sqlerrmcCcsid = typdef.getCcsidSbc();
821         }
822
823         netSqlca.setSqlerrd(sqlerrd);
824         netSqlca.setSqlwarnBytes(sqlwarn);
825         netSqlca.setSqlerrmcBytes(sqlerrmc, sqlerrmcCcsid);
826     }
827
828     // SQLDIAGGRP : FDOCA EARLY GROUP
829
private NetSqlca[] parseSQLDIAGGRP() throws DisconnectException, SqlException {
830         if (readFdocaOneByte() == CodePoint.NULLDATA) {
831             return null;
832         }
833
834         parseSQLDIAGSTT();
835         NetSqlca[] sqlca = parseSQLDIAGCI();
836         parseSQLDIAGCN();
837
838         return sqlca;
839     }
840
841     // SQL Diagnostics Statement Group Description - Identity 0xD3
842
// NULLDATA will be received for now
843
private void parseSQLDIAGSTT() throws DisconnectException, SqlException {
844         if (readFdocaOneByte() == CodePoint.NULLDATA) {
845             return;
846         }
847
848         // The server should send NULLDATA
849
netAgent_.accumulateChainBreakingReadExceptionAndThrow(
850                 new DisconnectException(netAgent_,
851                     new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
852                     "parseSQLDIAGSTT"));
853     }
854
855     // SQL Diagnostics Condition Information Array - Identity 0xF5
856
// SQLNUMROW; ROW LID 0x68; ELEMENT TAKEN 0(all); REP FACTOR 1
857
// SQLDCIROW; ROW LID 0xE5; ELEMENT TAKEN 0(all); REP FACTOR 0(all)
858
private NetSqlca[] parseSQLDIAGCI()
859             throws DisconnectException, SqlException {
860         int num = readFdocaTwoByteLength(); // SQLNUMGRP - SQLNUMROW
861
NetSqlca[] ret_val = null;
862         if (num != 0) {
863             ret_val = new NetSqlca[num];
864         }
865
866         for (int i = 0; i < num; i++) {
867             ret_val[i] = parseSQLDCROW();
868         }
869         return ret_val;
870     }
871
872     // SQL Diagnostics Connection Array - Identity 0xF6
873
// NULLDATA will be received for now
874
private void parseSQLDIAGCN() throws DisconnectException, SqlException {
875         if (readFdocaOneByte() == CodePoint.NULLDATA) {
876             return;
877         }
878         
879         // The server should send NULLDATA
880
netAgent_.accumulateChainBreakingReadExceptionAndThrow(
881                 new DisconnectException(netAgent_,
882                     new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
883                     "parseSQLDIAGCN"));
884     }
885
886     // SQL Diagnostics Condition Group Description
887
//
888
// SQLDCCODE; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
889
// SQLDCSTATE; PROTOCOL TYPE FCS; ENVLID Ox30; Lengeh Override 5
890
// SQLDCREASON; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
891
// SQLDCLINEN; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
892
// SQLDCROWN; PROTOCOL TYPE I8; ENVLID 0x16; Lengeh Override 8
893
// SQLDCER01; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
894
// SQLDCER02; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
895
// SQLDCER03; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
896
// SQLDCER04; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
897
// SQLDCPART; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
898
// SQLDCPPOP; PROTOCOL TYPE I4; ENVLID 0x02; Length Override 4
899
// SQLDCMSGID; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 10
900
// SQLDCMDE; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 8
901
// SQLDCPMOD; PROTOCOL TYPE FCS; ENVLID 0x30; Length Override 5
902
// SQLDCRDB; PROTOCOL TYPE VCS; ENVLID 0x32; Length Override 255
903
// SQLDCTOKS; PROTOCOL TYPE N-RLO; ENVLID 0xF7; Length Override 0
904
// SQLDCMSG_m; PROTOCOL TYPE NVMC; ENVLID 0x3F; Length Override 32672
905
// SQLDCMSG_S; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 32672
906
// SQLDCCOLN_m; PROTOCOL TYPE NVCM ; ENVLID 0x3F; Length Override 255
907
// SQLDCCOLN_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
908
// SQLDCCURN_m; PROTOCOL TYPE NVCM; ENVLID 0x3F; Length Override 255
909
// SQLDCCURN_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
910
// SQLDCPNAM_m; PROTOCOL TYPE NVCM; ENVLID 0x3F; Length Override 255
911
// SQLDCPNAM_s; PROTOCOL TYPE NVCS; ENVLID 0x33; Length Override 255
912
// SQLDCXGRP; PROTOCOL TYPE N-GDA; ENVLID 0xD3; Length Override 1
913
private NetSqlca parseSQLDCGRP()
914             throws DisconnectException, SqlException {
915         
916         int sqldcCode = readFdocaInt(); // SQLCODE
917
String JavaDoc sqldcState = readFdocaString(5,
918                 netAgent_.targetTypdef_.getCcsidSbcEncoding()); // SQLSTATE
919
int sqldcReason = readFdocaInt(); // REASON_CODE
920

921         skipFdocaBytes(12); // LINE_NUMBER + ROW_NUMBER
922

923         NetSqlca sqlca = new NetSqlca(netAgent_.netConnection_,
924                     sqldcCode,
925                     sqldcState,
926                     (byte[]) null);
927
928         skipFdocaBytes(49); // SQLDCER01-04 + SQLDCPART + SQLDCPPOP + SQLDCMSGID
929
// SQLDCMDE + SQLDCPMOD + RDBNAME
930
parseSQLDCTOKS(); // MESSAGE_TOKENS
931

932         String JavaDoc sqldcMsg = parseVCS(qrydscTypdef_); // MESSAGE_TEXT
933

934         if (sqldcMsg != null) {
935             sqlca.setSqlerrmcBytes(sqldcMsg.getBytes(),
936                     netAgent_.targetTypdef_.getByteOrder());
937         }
938
939         skipFdocaBytes(12); // COLUMN_NAME + PARAMETER_NAME + EXTENDED_NAMES
940

941         parseSQLDCXGRP(); // SQLDCXGRP
942
return sqlca;
943     }
944
945     // SQL Diagnostics Condition Row - Identity 0xE5
946
// SQLDCGRP; GROUP LID 0xD5; ELEMENT TAKEN 0(all); REP FACTOR 1
947
private NetSqlca parseSQLDCROW() throws DisconnectException, SqlException {
948         return parseSQLDCGRP();
949     }
950     
951     // SQL Diagnostics Condition Token Array - Identity 0xF7
952
// NULLDATA will be received for now
953
void parseSQLDCTOKS() throws DisconnectException, SqlException {
954         if (readFdocaOneByte() == CodePoint.NULLDATA) {
955             return;
956         }
957
958         // The server should send NULLDATA
959
netAgent_.accumulateChainBreakingReadExceptionAndThrow(
960                 new DisconnectException(netAgent_,
961                     new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
962                     "parseSQLDCTOKS"));
963     }
964
965     // SQL Diagnostics Extended Names Group Description - Identity 0xD5
966
// NULLDATA will be received for now
967
private void parseSQLDCXGRP() throws DisconnectException, SqlException {
968         if (readFdocaOneByte() == CodePoint.NULLDATA) {
969             return;
970         }
971
972         // The server should send NULLDATA
973
netAgent_.accumulateChainBreakingReadExceptionAndThrow(
974                 new DisconnectException(netAgent_,
975                     new ClientMessageId(SQLState.DRDA_COMMAND_NOT_IMPLEMENTED),
976                     "parseSQLDCXGRP"));
977     }
978
979     private String JavaDoc parseVCS(Typdef typdefInEffect) throws DisconnectException, SqlException {
980         return readFdocaString(readFdocaTwoByteLength(),
981                 typdefInEffect.getCcsidSbcEncoding());
982     }
983
984     // This is not used for column data.
985
private String JavaDoc readFdocaString(int length, String JavaDoc encoding) throws DisconnectException, SqlException {
986         if (length == 0) {
987             return null;
988         }
989
990         // For singleton select, the complete row always comes back, even if multiple query blocks are required,
991
// so there is no need to drive a flowFetch (continue query) request for singleton select.
992
if ((position_ + length) > lastValidBytePosition_) {
993             // Check for ENDQRYRM, throw SqlException if already received one.
994
checkAndThrowReceivedEndqryrm();
995
996             // Send CNTQRY to complete the row/rowset.
997
int lastValidByteBeforeFetch = completeSplitRow();
998
999             // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
1000
// throw a SqlException for the ENDQRYRM.
1001
checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
1002        }
1003
1004        String JavaDoc s = null;
1005
1006        try {
1007            s = new String JavaDoc(dataBuffer_, position_, length, encoding);
1008        } catch (java.io.UnsupportedEncodingException JavaDoc e) {
1009            netAgent_.accumulateChainBreakingReadExceptionAndThrow(
1010                new org.apache.derby.client.am.DisconnectException(
1011                    netAgent_,
1012                    new ClientMessageId(SQLState.NET_ENCODING_NOT_SUPPORTED),
1013                    e));
1014        }
1015
1016        position_ += length;
1017        return s;
1018    }
1019
1020    void allocateColumnOffsetAndLengthArrays() {
1021        columnDataPosition_ = new int[columns_];
1022        columnDataComputedLength_ = new int[columns_];
1023        isNull_ = new boolean[columns_];
1024    }
1025
1026    void setBlocking(int queryProtocolType) {
1027        if (queryProtocolType == CodePoint.LMTBLKPRC) {
1028            blocking_ = true;
1029        } else {
1030            blocking_ = false;
1031        }
1032    }
1033
1034    protected byte[] findExtdtaData(int column) {
1035        byte[] data = null;
1036
1037        // locate the EXTDTA bytes, if any
1038
Integer JavaDoc key = new Integer JavaDoc(column);
1039
1040        if (extdtaPositions_.containsKey(key)) {
1041            // found, get the data
1042
int extdtaQueuePosition = ((Integer JavaDoc) extdtaPositions_.get(key)).intValue();
1043            data = (byte[]) (extdtaData_.get(extdtaQueuePosition));
1044        }
1045
1046        return data;
1047    }
1048
1049    public Blob getBlobColumn_(int column, Agent agent) throws SqlException {
1050        int index = column - 1;
1051        int dataOffset;
1052        byte[] data;
1053        Blob blob = null;
1054
1055        // locate the EXTDTA bytes, if any
1056
data = findExtdtaData(column);
1057
1058        if (data != null) {
1059            // data found
1060
// set data offset based on the presence of a null indicator
1061
if (!nullable_[index]) {
1062                dataOffset = 0;
1063            } else {
1064                dataOffset = 1;
1065            }
1066
1067            blob = new Blob(data, agent, dataOffset);
1068        } else {
1069            blob = new Blob(new byte[0], agent, 0);
1070        }
1071
1072        return blob;
1073    }
1074
1075
1076    public Clob getClobColumn_(int column, Agent agent) throws SqlException {
1077        int index = column - 1;
1078        int dataOffset;
1079        byte[] data;
1080        Clob clob = null;
1081
1082        // locate the EXTDTA bytes, if any
1083
data = findExtdtaData(column);
1084
1085        if (data != null) {
1086            // data found
1087
// set data offset based on the presence of a null indicator
1088
if (!nullable_[index]) {
1089                dataOffset = 0;
1090            } else {
1091                dataOffset = 1;
1092            }
1093            clob = new Clob(agent, data, charsetName_[index], dataOffset);
1094        } else {
1095            // the locator is not valid, it is a zero-length LOB
1096
clob = new Clob(agent, "");
1097        }
1098
1099        return clob;
1100    }
1101
1102    public byte[] getClobBytes_(int column, int[] dataOffset /*output*/) throws SqlException {
1103        int index = column - 1;
1104        byte[] data = null;
1105
1106        // locate the EXTDTA bytes, if any
1107
data = findExtdtaData(column);
1108
1109        if (data != null) {
1110            // data found
1111
// set data offset based on the presence of a null indicator
1112
if (!nullable_[index]) {
1113                dataOffset[0] = 0;
1114            } else {
1115                dataOffset[0] = 1;
1116            }
1117        }
1118
1119        return data;
1120    }
1121
1122    // this is really an event-callback from NetStatementReply.parseSQLDTARDarray()
1123
void initializeColumnInfoArrays(Typdef typdef,
1124                                    int columnCount, int targetSqlamForTypdef) throws DisconnectException {
1125        qrydscTypdef_ = typdef;
1126
1127        // Allocate arrays to hold the descriptor information.
1128
setNumberOfColumns(columnCount);
1129        fdocaLength_ = new int[columnCount];
1130        isGraphic_ = new boolean[columnCount];
1131        typeToUseForComputingDataLength_ = new int[columnCount];
1132        targetSqlamForTypdef_ = targetSqlamForTypdef;
1133    }
1134
1135
1136    int ensureSpaceForDataBuffer(int ddmLength) {
1137        if (dataBuffer_ == null) {
1138            allocateDataBuffer();
1139        }
1140        //super.resultSet.cursor.clearColumnDataOffsetsCache();
1141
// Need to know how many bytes to ask from the Reply object,
1142
// and handle the case where buffer is not big enough for all the bytes.
1143
// Get the length in front of the code point first.
1144

1145        int bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
1146
1147        // Make sure the buffer has at least ddmLength amount of room left.
1148
// If not, expand the buffer before calling the getQrydtaData() method.
1149
if (bytesAvailableInDataBuffer < ddmLength) {
1150
1151            // Get a new buffer that is twice the size of the current buffer.
1152
// Copy the contents from the old buffer to the new buffer.
1153
int newBufferSize = 2 * dataBuffer_.length;
1154
1155            while (newBufferSize < ddmLength) {
1156                newBufferSize = 2 * newBufferSize;
1157            }
1158
1159            byte[] tempBuffer = new byte[newBufferSize];
1160
1161            System.arraycopy(dataBuffer_,
1162                    0,
1163                    tempBuffer,
1164                    0,
1165                    lastValidBytePosition_);
1166
1167            // Make the new buffer the dataBuffer.
1168
dataBuffer_ = tempBuffer;
1169
1170            // Recalculate bytesAvailableInDataBuffer
1171
bytesAvailableInDataBuffer = dataBuffer_.length - lastValidBytePosition_;
1172        }
1173        return bytesAvailableInDataBuffer;
1174    }
1175
1176    protected void getMoreData_() throws SqlException {
1177        // reset the dataBuffer_ before getting more data if cursor is foward-only.
1178
// getMoreData() is only called in Cursor.next() when current position is
1179
// equal to lastValidBytePosition_.
1180
if (netResultSet_.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) {
1181            resetDataBuffer();
1182        }
1183        netResultSet_.flowFetch();
1184    }
1185
1186    public void nullDataForGC() // memory leak fix
1187
{
1188        super.nullDataForGC();
1189        qrydscTypdef_ = null;
1190        typeToUseForComputingDataLength_ = null;
1191        isGraphic_ = null;
1192
1193        if (extdtaPositions_ != null) {
1194            extdtaPositions_.clear();
1195        }
1196        extdtaPositions_ = null;
1197
1198        if (extdtaData_ != null) {
1199            extdtaData_.clear();
1200        }
1201        extdtaData_ = null;
1202    }
1203
1204    // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD.
1205
// This means some error has occurred on the server and the server is terminating the query.
1206
// Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already
1207
// been received. If so, do not send CNTQRY because the cursor is already closed on the server.
1208
// Instead, throw a SqlException. Since we did not receive a complete row, it is not safe to
1209
// allow the application to continue to access the ResultSet, so we close it.
1210
private void checkAndThrowReceivedEndqryrm() throws SqlException {
1211        // If we are in a split row, and before sending CNTQRY, check whether an ENDQRYRM
1212
// has been received.
1213
if (!netResultSet_.openOnServer_) {
1214            SqlException sqlException = null;
1215            int sqlcode = org.apache.derby.client.am.Utils.getSqlcodeFromSqlca(netResultSet_.queryTerminatingSqlca_);
1216            if (sqlcode < 0) {
1217                sqlException = new SqlException(agent_.logWriter_, netResultSet_.queryTerminatingSqlca_);
1218            } else {
1219                sqlException = new SqlException(agent_.logWriter_,
1220                    new ClientMessageId(SQLState.NET_QUERY_PROCESSING_TERMINATED));
1221            }
1222            try {
1223                netResultSet_.closeX(); // the auto commit logic is in closeX()
1224
} catch (SqlException e) {
1225                sqlException.setNextException(e);
1226            }
1227            throw sqlException;
1228        }
1229    }
1230
1231    private void checkAndThrowReceivedEndqryrm(int lastValidBytePositionBeforeFetch) throws SqlException {
1232        // if we have received more data in the dataBuffer_, just return.
1233
if (lastValidBytePosition_ > lastValidBytePositionBeforeFetch) {
1234            return;
1235        }
1236        checkAndThrowReceivedEndqryrm();
1237    }
1238
1239    private int completeSplitRow() throws DisconnectException, SqlException {
1240        int lastValidBytePositionBeforeFetch = 0;
1241        if (netResultSet_ != null && netResultSet_.scrollable_) {
1242            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1243            netResultSet_.flowFetchToCompleteRowset();
1244        } else {
1245            // Shift partial row to the beginning of the dataBuffer
1246
shiftPartialRowToBeginning();
1247            resetCurrentRowPosition();
1248            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1249            netResultSet_.flowFetch();
1250        }
1251        return lastValidBytePositionBeforeFetch;
1252    }
1253
1254    private int completeSplitRow(int index) throws DisconnectException, SqlException {
1255        int lastValidBytePositionBeforeFetch = 0;
1256        if (netResultSet_ != null && netResultSet_.scrollable_) {
1257            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1258            netResultSet_.flowFetchToCompleteRowset();
1259        } else {
1260            // Shift partial row to the beginning of the dataBuffer
1261
shiftPartialRowToBeginning();
1262            adjustColumnOffsetsForColumnsPreviouslyCalculated(index);
1263            resetCurrentRowPosition();
1264            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
1265            netResultSet_.flowFetch();
1266        }
1267        return lastValidBytePositionBeforeFetch;
1268    }
1269
1270    private int[] allocateColumnDataPositionArray(int row) {
1271        int[] columnDataPosition;
1272        if (columnDataPositionCache_.size() == row) {
1273            columnDataPosition = new int[columns_];
1274            columnDataPositionCache_.add(columnDataPosition);
1275        } else {
1276            columnDataPosition = (int[]) columnDataPositionCache_.get(row);
1277        }
1278        return columnDataPosition;
1279    }
1280
1281    private int[] allocateColumnDataComputedLengthArray(int row) {
1282        int[] columnDataComputedLength;
1283        if (columnDataLengthCache_.size() == row) {
1284            columnDataComputedLength = new int[columns_];
1285            columnDataLengthCache_.add(columnDataComputedLength);
1286        } else {
1287            columnDataComputedLength = (int[]) columnDataLengthCache_.get(row);
1288        }
1289        return columnDataComputedLength;
1290    }
1291
1292    private boolean[] allocateColumnDataIsNullArray(int row) {
1293        boolean[] columnDataIsNull;
1294        if (columnDataIsNullCache_.size() <= row) {
1295            columnDataIsNull = new boolean[columns_];
1296            columnDataIsNullCache_.add(columnDataIsNull);
1297        } else {
1298            columnDataIsNull = (boolean[]) columnDataIsNullCache_.get(row);
1299        }
1300        return columnDataIsNull;
1301    }
1302
1303    protected int getDecimalLength(int index) {
1304        return (((fdocaLength_[index] >> 8) & 0xff) + 2) / 2;
1305    }
1306
1307    /**
1308     * Set the value of value of allRowsReceivedFromServer_.
1309     *
1310     * @param b a <code>boolean</code> value indicating whether all
1311     * rows are received from the server
1312     */

1313    public final void setAllRowsReceivedFromServer(boolean b) {
1314        if (b && qryclsimpEnabled_) {
1315            netResultSet_.markClosedOnServer();
1316        }
1317        super.setAllRowsReceivedFromServer(b);
1318    }
1319
1320    /**
1321     * Set a flag indicating whether QRYCLSIMP is enabled.
1322     *
1323     * @param flag true if QRYCLSIMP is enabled
1324     */

1325    final void setQryclsimpEnabled(boolean flag) {
1326        qryclsimpEnabled_ = flag;
1327    }
1328
1329    /**
1330     * Check whether QRYCLSIMP is enabled on this cursor.
1331     *
1332     * @return true if QRYCLSIMP is enabled
1333     */

1334    final boolean getQryclsimpEnabled() {
1335        return qryclsimpEnabled_;
1336    }
1337}
1338
Popular Tags