001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc.fetch;
012:
013: import com.versant.core.common.BindingSupportImpl;
014: import com.versant.core.common.Debug;
015:
016: import java.sql.ResultSet;
017: import java.sql.PreparedStatement;
018: import java.sql.SQLException;
019:
020: /**
021: * This maintains information about a FetchSpec used during a fetch operation.
022: * All the fields of the FetchSpec and FetchOp's themselves are read only
023: * once the spec has been prepared. This makes it possible to use the same
024: * FetchSpec from different threads simultaneously.
025: */
026: public class FetchResultImp implements FetchResult {
027:
028: private FetchSpec spec;
029: private String sql;
030: private PreparedStatement ps;
031: private ResultSet rs;
032: private boolean scrollable;
033: private boolean haveRow;
034: private Object[] opData;
035:
036: public FetchResultImp(FetchSpec spec, PreparedStatement ps,
037: String sql, boolean scrollable) {
038: this .spec = spec;
039: this .ps = ps;
040: this .sql = sql;
041: this .scrollable = scrollable;
042: opData = new Object[spec.getFetchOpCount()];
043: }
044:
045: public void execute() {
046: if (rs != null) {
047: throw BindingSupportImpl.getInstance().internal(
048: "query has already been executed");
049: }
050: checkClosed();
051: try {
052: rs = ps.executeQuery();
053: } catch (Exception e) {
054: throw spec.getSqlDriver().mapException(e,
055: "Error executing query: " + e + "\nSQL:\n" + sql,
056: true);
057: }
058: }
059:
060: public void cancel() {
061: if (rs != null) {
062: try {
063: ps.cancel();
064: } catch (SQLException e) {
065: throw spec.getSqlDriver().mapException(e,
066: e + "\nSQL:\n" + sql, true);
067: }
068: }
069: }
070:
071: public void close() {
072: if (isClosed()) {
073: return;
074: }
075: if (rs != null) {
076: try {
077: rs.close();
078: } catch (Exception e) {
079: // ignore
080: }
081: rs = null;
082: }
083: try {
084: ps.close();
085: } catch (SQLException e) {
086: // ignore
087: }
088: ps = null;
089: spec.fetchResultClosed(this );
090: opData = null;
091: }
092:
093: public boolean isClosed() {
094: return ps == null;
095: }
096:
097: public boolean hasNext() {
098: if (ps == null) {
099: return false;
100: }
101: if (rs == null) {
102: execute();
103: }
104: try {
105: if (haveRow || (haveRow = rs.next())) {
106: return true;
107: } else {
108: close();
109: return false;
110: }
111: } catch (Exception e) {
112: throw spec.getSqlDriver().mapException(e, e.toString(),
113: true);
114: }
115: }
116:
117: public Object next() {
118: if (haveRow || hasNext()) {
119: Object row = spec.createRow(this );
120: haveRow = false;
121: return row;
122: } else {
123: throw BindingSupportImpl.getInstance().internal(
124: "no more rows: " + this );
125: }
126: }
127:
128: public void remove() {
129: throw new UnsupportedOperationException();
130: }
131:
132: public boolean isScrollable() {
133: return scrollable;
134: }
135:
136: private void checkClosed() {
137: if (ps == null) {
138: throw BindingSupportImpl.getInstance().internal(
139: "FetchResult has been closed");
140: }
141: }
142:
143: public int size() {
144: if (Debug.DEBUG) {
145: checkScrollable();
146: }
147: try {
148: if (rs == null) {
149: execute();
150: }
151: if (rs.last()) {
152: return rs.getRow();
153: } else {
154: return 0;
155: }
156: } catch (Exception e) {
157: throw spec.getSqlDriver().mapException(e, e.toString(),
158: true);
159: }
160: }
161:
162: public Object get(int index) {
163: if (Debug.DEBUG) {
164: checkScrollable();
165: }
166: try {
167: if (rs == null) {
168: execute();
169: }
170: if (rs.absolute(index + 1)) {
171: return spec.createRow(this );
172: } else {
173: throw BindingSupportImpl.getInstance().internal(
174: "invalud index " + index + ": " + this );
175: }
176: } catch (Exception e) {
177: throw spec.getSqlDriver().mapException(e, e.toString(),
178: true);
179: }
180: }
181:
182: private void checkScrollable() {
183: if (!scrollable) {
184: throw BindingSupportImpl.getInstance().internal(
185: "not scrollable: " + this );
186: }
187: }
188:
189: /**
190: * Get data for op.
191: */
192: public Object getData(FetchOp op) {
193: if (Debug.DEBUG) {
194: checkOp(op);
195: }
196: return opData[op.getIndex()];
197: }
198:
199: /**
200: * Set data object for op.
201: */
202: public void setData(FetchOp op, Object data) {
203: if (Debug.DEBUG) {
204: checkOp(op);
205: }
206: opData[op.getIndex()] = data;
207: }
208:
209: private void checkOp(FetchOp op) {
210: if (op == null) {
211: throw BindingSupportImpl.getInstance().internal(
212: "op is null: " + this );
213: }
214: if (op.getSpec() != spec) {
215: throw BindingSupportImpl.getInstance().internal(
216: "spec mismatch: " + this + ", op.getSpec() = "
217: + op.getSpec() + ", op " + op);
218: }
219: }
220:
221: public String toString() {
222: return "FetchResult 0x"
223: + Integer.toHexString(System.identityHashCode(this ))
224: + (isClosed() ? " CLOSED" : "") + " spec " + spec;
225: }
226:
227: public ResultSet getResultSet() {
228: return rs;
229: }
230:
231: public FetchSpec getFetchSpec() {
232: return spec;
233: }
234:
235: public PreparedStatement getPreparedStatement() {
236: return ps;
237: }
238:
239: }
|