001: /*
002:
003: Derby - Class org.apache.derby.impl.drda.DRDAResultSet
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.drda;
023:
024: import java.sql.ResultSet;
025: import java.sql.ResultSetMetaData;
026: import java.sql.SQLException;
027: import java.sql.Types;
028: import java.util.ArrayList;
029:
030: import org.apache.derby.iapi.jdbc.EngineResultSet;
031:
032: /**
033: DRDAResultSet holds result set information
034: */
035: class DRDAResultSet {
036: //NOTE!
037: //
038: // Since DRDAResultSets are reused, ALL variables should be set
039: // to their default values in reset().
040:
041: // resultSet states are NOT_OPENED and SUSPENDED
042: protected static final int NOT_OPENED = 1;
043: protected static final int SUSPENDED = 2;
044: public static final int QRYCLSIMP_DEFAULT = CodePoint.QRYCLSIMP_NO;
045:
046: boolean explicitlyClosed = false;
047:
048: int state;
049: protected boolean hasdata = true;
050: protected int[] rsLens; // result length for each column
051: private int[] rsDRDATypes; // DRDA Types of the result set columns
052: private int[] rsPrecision; // result precision for Decimal types
053: private int[] rsScale; // result sale for Decimal types
054:
055: protected int[] outovr_drdaType; // Output override DRDA type and length
056:
057: protected int withHoldCursor; // hold cursor after commit attribute
058: protected int scrollType = ResultSet.TYPE_FORWARD_ONLY; // Sensitive or Insensitive scroll attribute
059: protected int concurType; // Concurency type
060: protected long rowCount; // Number of rows we have processed
061: private ResultSet rs; // Current ResultSet
062:
063: protected int blksize; // Query block size
064: protected int maxblkext; // Maximum number of extra blocks
065: protected int outovropt; // Output Override option
066: protected int qryclsimp; // Implicit Query Close Setting
067: protected boolean qryrelscr; // Query relative scrolling
068: protected long qryrownbr; // Query row number
069: protected boolean qryrfrtbl; // Query refresh answer set table
070: protected int qryscrorn; // Query scroll orientation
071: protected boolean qryrowsns; // Query row sensitivity
072: protected boolean qryblkrst; // Query block reset
073: protected boolean qryrtndta; // Query returns data
074: protected int qryrowset; // Query row set
075: private int qryprctyp; // Protocol type
076: private boolean gotPrctyp; // save the result, for performance
077: protected int rtnextdta; // Return of EXTDTA option
078: protected int nbrrow; // number of fetch or insert rows
079: protected byte[] rslsetflg; // Result Set Flags
080:
081: private ArrayList extDtaObjects; // Arraylist of Blobs and Clobs
082: // Return Values to
083: // send with extdta objects.
084:
085: private ArrayList rsExtPositions;
086:
087: protected ConsistencyToken pkgcnstkn; // Unique consistency token for ResultSet 0
088:
089: // splitQRYDTA is normally null. If it is non-null, it means that
090: // the last QRYDTA response which was sent for this statement was
091: // split according to the LMTBLKPRC protocol, and this array contains
092: // the bytes that didn't fit. These bytes should be the first bytes
093: // emitted in the next QRYDTA response to a CNTQRY request.
094: private byte[] splitQRYDTA;
095:
096: DRDAResultSet() {
097: state = NOT_OPENED;
098: // Initialize qryclsimp to NO. Only result sets requested by
099: // an OPNQRY command should be implicitly closed. OPNQRY will
100: // set qryclsimp later in setOPNQRYOptions().
101: qryclsimp = CodePoint.QRYCLSIMP_NO;
102: }
103:
104: /**
105: * Set result set and initialize type array.
106: *
107: * @param value
108: *
109: */
110:
111: protected void setResultSet(ResultSet value) throws SQLException {
112: int numCols;
113: rs = value;
114: gotPrctyp = false;
115: if (value != null) {
116: numCols = rs.getMetaData().getColumnCount();
117: rsDRDATypes = new int[numCols];
118: }
119: explicitlyClosed = false;
120: }
121:
122: /**
123: * set consistency token for this resultSet
124: *
125: */
126: protected void setPkgcnstkn(ConsistencyToken pkgcnstkn) {
127: this .pkgcnstkn = pkgcnstkn;
128: }
129:
130: /**
131: *
132: * @return the underlying java.sql.ResultSet
133: */
134: protected ResultSet getResultSet() {
135: return rs;
136: }
137:
138: public void setSplitQRYDTA(byte[] data) {
139: splitQRYDTA = data;
140: }
141:
142: public byte[] getSplitQRYDTA() {
143: return splitQRYDTA;
144: }
145:
146: /**
147: * Set ResultSet DRDA DataTypes
148: * @param value drdaTypes for columns.
149: **/
150: protected void setRsDRDATypes(int[] value) {
151: rsDRDATypes = value;
152:
153: }
154:
155: /**
156: *@return ResultSet DRDA DataTypes
157: **/
158:
159: protected int[] getRsDRDATypes() {
160: // use the given override if it is present
161: if (outovr_drdaType != null)
162: return outovr_drdaType;
163: return rsDRDATypes;
164: }
165:
166: /**
167: * set resultset/out parameter precision
168: *
169: * @param index - starting with 1
170: * @param precision
171: */
172: protected void setRsPrecision(int index, int precision) {
173: if (rsPrecision == null)
174: rsPrecision = new int[rsDRDATypes.length];
175: rsPrecision[index - 1] = precision;
176: }
177:
178: /**
179: * get resultset /out paramter precision
180: * @param index -starting with 1
181: * @return precision of column
182: */
183: protected int getRsPrecision(int index) {
184: if (rsPrecision == null)
185: return 0;
186: return rsPrecision[index - 1];
187: }
188:
189: /**
190: * set resultset/out parameter scale
191: *
192: * @param index - starting with 1
193: * @param scale
194: */
195: protected void setRsScale(int index, int scale) {
196: if (rsScale == null)
197: rsScale = new int[rsDRDATypes.length];
198: rsScale[index - 1] = scale;
199: }
200:
201: /**
202: * get resultset /out paramter scale
203: * @param index -starting with 1
204: * @return scale of column
205: */
206: protected int getRsScale(int index) {
207: if (rsScale == null)
208: return 0;
209:
210: return rsScale[index - 1];
211: }
212:
213: /**
214: * set resultset/out parameter DRDAType
215: *
216: * @param index - starting with 1
217: * @param type
218: */
219: protected void setRsDRDAType(int index, int type) {
220: rsDRDATypes[index - 1] = type;
221:
222: }
223:
224: /**
225: * get resultset/out parameter DRDAType
226: *
227: * @param index - starting with 1
228: * @return DRDA Type of column
229: */
230: protected int getRsDRDAType(int index) {
231: return rsDRDATypes[index - 1];
232: }
233:
234: /**
235: * set resultset DRDA Len
236: *
237: * @param index - starting with 1
238: * @param value
239: */
240: protected void setRsLen(int index, int value) {
241: if (rsLens == null)
242: rsLens = new int[rsDRDATypes.length];
243: rsLens[index - 1] = value;
244:
245: }
246:
247: /**
248: * get resultset DRDALen
249: * @param index - starting with 1
250: * @return length of column value
251: */
252: protected int getRsLen(int index) {
253: return rsLens[index - 1];
254: }
255:
256: /**
257: * Add extDtaObject
258: * @param o - object to add
259: */
260: protected void addExtDtaObject(Object o, int jdbcIndex) {
261: if (extDtaObjects == null)
262: extDtaObjects = new java.util.ArrayList();
263: extDtaObjects.add(o);
264:
265: if (rsExtPositions == null)
266: rsExtPositions = new java.util.ArrayList();
267:
268: // need to record the 0 based position so subtract 1
269: rsExtPositions.add(new Integer(jdbcIndex - 1));
270:
271: }
272:
273: /**
274: * Clear externalized lob objects in current result set
275: */
276: protected void clearExtDtaObjects() {
277: if (extDtaObjects != null)
278: extDtaObjects.clear();
279: if (rsExtPositions != null)
280: rsExtPositions.clear();
281:
282: }
283:
284: /*
285: * Is lob object nullable
286: * @param index - offset starting with 0
287: * @return true if object is nullable
288: */
289: protected boolean isExtDtaValueNullable(int index) {
290: if ((rsExtPositions == null)
291: || rsExtPositions.get(index) == null)
292: return false;
293:
294: int colnum = ((Integer) rsExtPositions.get(index)).intValue();
295:
296: if (FdocaConstants.isNullable((getRsDRDATypes())[colnum]))
297: return true;
298: else
299: return false;
300: }
301:
302: /**
303: * Get the extData Objects
304: *
305: * @return ArrayList with extdta
306: */
307: protected ArrayList getExtDtaObjects() {
308: return extDtaObjects;
309: }
310:
311: /**
312: * Set the extData Objects
313: */
314: protected void setExtDtaObjects(ArrayList a) {
315: extDtaObjects = a;
316: }
317:
318: /**
319: * This method closes the JDBC objects and frees up all references held by
320: * this object.
321: *
322: * @throws SQLException
323: */
324: protected void close() throws SQLException {
325: if (rs != null)
326: rs.close();
327: rs = null;
328: outovr_drdaType = null;
329: rsLens = null;
330: rsDRDATypes = null;
331: rsPrecision = null;
332: rsScale = null;
333: extDtaObjects = null;
334: splitQRYDTA = null;
335: rsExtPositions = null;
336: }
337:
338: /**
339: * This method resets the state of this DRDAResultset object so that it can
340: * be re-used. This method should reset all variables of this class.
341: *
342: */
343: protected void reset() {
344: explicitlyClosed = false;
345: state = NOT_OPENED;
346: hasdata = true;
347: rsLens = null;
348: rsDRDATypes = null;
349: rsPrecision = null;
350: rsScale = null;
351:
352: outovr_drdaType = null;
353:
354: withHoldCursor = 0;
355: scrollType = ResultSet.TYPE_FORWARD_ONLY;
356: concurType = 0;
357: rowCount = 0;
358: rs = null;
359:
360: blksize = 0;
361: maxblkext = 0;
362: outovropt = 0;
363: qryclsimp = CodePoint.QRYCLSIMP_NO;
364: qryrelscr = false;
365: qryrownbr = 0;
366: qryrfrtbl = false;
367: qryscrorn = 0;
368: qryrowsns = false;
369: qryblkrst = false;
370: qryrtndta = false;
371: qryrowset = 0;
372: qryprctyp = 0;
373: gotPrctyp = false;
374: rtnextdta = 0;
375: nbrrow = 0;
376: rslsetflg = null;
377:
378: extDtaObjects = null;
379: rsExtPositions = null;
380: pkgcnstkn = null;
381: splitQRYDTA = null;
382: }
383:
384: /**
385: * Explicitly close the result set by CLSQRY
386: * needed to check for double close.
387: */
388: protected void CLSQRY() {
389: explicitlyClosed = true;
390: }
391:
392: /*
393: * @return whether CLSQRY has been called on the
394: * current result set.
395: */
396: protected boolean wasExplicitlyClosed() {
397: return explicitlyClosed;
398: }
399:
400: /****
401: * Check to see if the result set for this statement
402: * has at least one column that is BLOB/CLOB.
403: * @return True if the result has at least one blob/clob
404: * column; false otherwise.
405: ****/
406:
407: protected boolean hasLobColumns() throws SQLException {
408: ResultSetMetaData rsmd = rs.getMetaData();
409: int ncols = rsmd.getColumnCount();
410: for (int i = 1; i <= ncols; i++) {
411: int type = rsmd.getColumnType(i);
412: if (type == Types.BLOB || type == Types.CLOB)
413: return true;
414: }
415: return false;
416: }
417:
418: /**
419: * Get the cursor name for the ResultSet
420: */
421: public String getResultSetCursorName() throws SQLException {
422:
423: if (rs != null)
424: return rs.getCursorName();
425: else
426: return null;
427: }
428:
429: protected int getQryprctyp() throws SQLException {
430: if (!gotPrctyp && qryprctyp == CodePoint.LMTBLKPRC) {
431: gotPrctyp = true;
432: if (rs == null || ((EngineResultSet) rs).isForUpdate() ||
433: /* for now we are not supporting LOB under LMTBLKPRC. drda spec only
434: * disallows LOB under LMTBLKPRC if OUTOVR is also for ANY CNTQRY reply.
435: * To support LOB, QRYDTA protocols for LOB will need to be changed.
436: */
437: hasLobColumns()) {
438: qryprctyp = CodePoint.FIXROWPRC;
439: }
440: }
441: return qryprctyp;
442: }
443:
444: protected void setQryprctyp(int qryprctyp) {
445: this .qryprctyp = qryprctyp;
446: }
447:
448: /**
449: * is ResultSet closed
450: * @return whether the resultSet is closed
451: */
452: protected boolean isClosed() {
453: return (state == NOT_OPENED);
454: }
455:
456: /**
457: * Set state to SUSPENDED (result set is opened)
458: */
459: protected void suspend() {
460: state = SUSPENDED;
461: }
462:
463: protected String toDebugString(String indent) {
464: String s = indent
465: + "***** DRDASResultSet toDebugString ******\n";
466: s += indent + "State:" + getStateString(state) + "\n";
467: s += indent + "pkgcnstkn: {" + pkgcnstkn + "}\n";
468: s += indent + "cursor Name: ";
469: String cursorName = null;
470: try {
471: if (rs != null)
472: cursorName = rs.getCursorName();
473: } catch (SQLException se) {
474: cursorName = "invalid rs";
475: }
476: s += indent + cursorName + "\n";
477:
478: return s;
479: }
480:
481: private String getStateString(int i) {
482: switch (i) {
483: case NOT_OPENED:
484: return "NOT_OPENED";
485: case SUSPENDED:
486: return "SUSPENDED";
487: default:
488: return "UNKNOWN_STATE";
489: }
490:
491: }
492:
493: /**
494: * Sets the OPNQRYOptions. For more information on the meaning of these
495: * values consult the DRDA Technical Standard document.
496: *
497: * @param blksize Query block Size
498: * @param qryblkctl Use to set the query protocol type
499: * @param maxblkext Maximum number of extra blocks
500: * @param outovropt Output override option
501: * @param qryrowset Query row set
502: * @param qryclsimpl Implicit query close setting
503: */
504: protected void setOPNQRYOptions(int blksize, int qryblkctl,
505: int maxblkext, int outovropt, int qryrowset, int qryclsimpl) {
506: this .blksize = blksize;
507: setQryprctyp(qryblkctl);
508: this .maxblkext = maxblkext;
509: this .outovropt = outovropt;
510: this .qryrowset = qryrowset;
511: this .qryclsimp = (qryclsimpl == CodePoint.QRYCLSIMP_SERVER_CHOICE) ? DRDAResultSet.QRYCLSIMP_DEFAULT
512: : qryclsimpl;
513:
514: // Assume that we are returning data until a CNTQRY command
515: // tells us otherwise. (DERBY-822)
516: qryrtndta = true;
517:
518: // For scrollable result sets, we don't know the fetch
519: // orientation until we get a CNTQRY command. Set orientation
520: // and row number to make pre-fetching possible. (DERBY-822)
521: qryscrorn = CodePoint.QRYSCRREL;
522: qryrownbr = 1;
523: }
524: }
|