Source code: com/mysql/jdbc/RowDataDynamic.java
1 /*
2 Copyright (C) 2002-2004 MySQL AB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as
6 published by the Free Software Foundation.
7
8
9 There are special exceptions to the terms and conditions of the GPL
10 as it is applied to this software. View the full text of the
11 exception exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
12 software distribution.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 */
24 package com.mysql.jdbc;
25
26 import java.io.IOException;
27 import java.sql.SQLException;
28
29
30 /**
31 * Allows streaming of MySQL data.
32 *
33 * @author dgan
34 * @version $Id: RowDataDynamic.java,v 1.8.2.9 2004/08/09 22:15:10 mmatthew Exp $
35 */
36 public class RowDataDynamic implements RowData {
37 private MysqlIO io;
38 private byte[][] nextRow;
39 private boolean isAfterEnd = false;
40 private boolean isAtEnd = false;
41 private boolean streamerClosed = false;
42 private int columnCount;
43 private int index = -1;
44 private long lastSuccessfulReadTimeMs = 0;
45 private long netWriteTimeoutMs = 0;
46 private ResultSet owner;
47
48 /**
49 * Creates a new RowDataDynamic object.
50 *
51 * @param io DOCUMENT ME!
52 * @param colCount DOCUMENT ME!
53 *
54 * @throws SQLException DOCUMENT ME!
55 */
56 public RowDataDynamic(MysqlIO io, int colCount) throws SQLException {
57 this.io = io;
58 this.columnCount = colCount;
59 nextRecord();
60 }
61
62 /**
63 * Returns true if we got the last element.
64 *
65 * @return true if after last row
66 *
67 * @throws SQLException if a database error occurs
68 */
69 public boolean isAfterLast() throws SQLException {
70 return isAfterEnd;
71 }
72
73 /**
74 * Only works on non dynamic result sets.
75 *
76 * @param index row number to get at
77 *
78 * @return row data at index
79 *
80 * @throws SQLException if a database error occurs
81 */
82 public byte[][] getAt(int index) throws SQLException {
83 notSupported();
84
85 return null;
86 }
87
88 /**
89 * Returns if iteration has not occured yet.
90 *
91 * @return true if before first row
92 *
93 * @throws SQLException if a database error occurs
94 */
95 public boolean isBeforeFirst() throws SQLException {
96 return index < 0;
97 }
98
99 /**
100 * Moves the current position in the result set to the given row number.
101 *
102 * @param rowNumber row to move to
103 *
104 * @throws SQLException if a database error occurs
105 */
106 public void setCurrentRow(int rowNumber) throws SQLException {
107 notSupported();
108 }
109
110 /**
111 * @see com.mysql.jdbc.RowData#setOwner(com.mysql.jdbc.ResultSet)
112 */
113 public void setOwner(ResultSet rs) {
114 this.owner = rs;
115 }
116
117 /**
118 * @see com.mysql.jdbc.RowData#getOwner()
119 */
120 public ResultSet getOwner() {
121 return this.owner;
122 }
123
124 /**
125 * Returns the current position in the result set as a row number.
126 *
127 * @return the current row number
128 *
129 * @throws SQLException if a database error occurs
130 */
131 public int getCurrentRowNumber() throws SQLException {
132 notSupported();
133
134 return -1;
135 }
136
137 /**
138 * Returns true if the result set is dynamic. This means that move back and
139 * move forward won't work because we do not hold on to the records.
140 *
141 * @return true if this result set is streaming from the server
142 */
143 public boolean isDynamic() {
144 return true;
145 }
146
147 /**
148 * Has no records.
149 *
150 * @return true if no records
151 *
152 * @throws SQLException if a database error occurs
153 */
154 public boolean isEmpty() throws SQLException {
155 notSupported();
156
157 return false;
158 }
159
160 /**
161 * Are we on the first row of the result set?
162 *
163 * @return true if on first row
164 *
165 * @throws SQLException if a database error occurs
166 */
167 public boolean isFirst() throws SQLException {
168 notSupported();
169
170 return false;
171 }
172
173 /**
174 * Are we on the last row of the result set?
175 *
176 * @return true if on last row
177 *
178 * @throws SQLException if a database error occurs
179 */
180 public boolean isLast() throws SQLException {
181 notSupported();
182
183 return false;
184 }
185
186 /**
187 * Adds a row to this row data.
188 *
189 * @param row the row to add
190 *
191 * @throws SQLException if a database error occurs
192 */
193 public void addRow(byte[][] row) throws SQLException {
194 notSupported();
195 }
196
197 /**
198 * Moves to after last.
199 *
200 * @throws SQLException if a database error occurs
201 */
202 public void afterLast() throws SQLException {
203 notSupported();
204 }
205
206 /**
207 * Moves to before first.
208 *
209 * @throws SQLException if a database error occurs
210 */
211 public void beforeFirst() throws SQLException {
212 notSupported();
213 }
214
215 /**
216 * Moves to before last so next el is the last el.
217 *
218 * @throws SQLException if a database error occurs
219 */
220 public void beforeLast() throws SQLException {
221 notSupported();
222 }
223
224 /**
225 * We're done.
226 *
227 * @throws SQLException if a database error occurs
228 */
229 public void close() throws SQLException {
230 //drain the rest of the records.
231 int count = 0;
232
233 while (this.hasNext()) {
234 this.next();
235
236 count++;
237
238 if (count == 100) {
239 Thread.yield();
240 count = 0;
241 }
242 }
243 }
244
245 /**
246 * Returns true if another row exsists.
247 *
248 * @return true if more rows
249 *
250 * @throws SQLException if a database error occurs
251 */
252 public boolean hasNext() throws SQLException {
253 boolean hasNext = (nextRow != null);
254
255 if (!hasNext && !streamerClosed) {
256 io.closeStreamer(this);
257 streamerClosed = true;
258 }
259
260 return hasNext;
261 }
262
263 /**
264 * Moves the current position relative 'rows' from the current position.
265 *
266 * @param rows the relative number of rows to move
267 *
268 * @throws SQLException if a database error occurs
269 */
270 public void moveRowRelative(int rows) throws SQLException {
271 notSupported();
272 }
273
274 /**
275 * Returns the next row.
276 *
277 * @return the next row value
278 *
279 * @throws SQLException if a database error occurs
280 */
281 public byte[][] next() throws SQLException {
282 index++;
283
284 byte[][] ret = nextRow;
285 nextRecord();
286
287 return ret;
288 }
289
290 /**
291 * Removes the row at the given index.
292 *
293 * @param index the row to move to
294 *
295 * @throws SQLException if a database error occurs
296 */
297 public void removeRow(int index) throws SQLException {
298 notSupported();
299 }
300
301 /**
302 * Only works on non dynamic result sets.
303 *
304 * @return the size of this row data
305 */
306 public int size() {
307 return RESULT_SET_SIZE_UNKNOWN;
308 }
309
310 private void nextRecord() throws SQLException {
311 try {
312 if (!isAtEnd) {
313 nextRow = io.nextRow((int) columnCount);
314
315 if (nextRow == null) {
316 isAtEnd = true;
317 }
318
319 this.lastSuccessfulReadTimeMs = System.currentTimeMillis();
320 } else {
321 isAfterEnd = true;
322 }
323 } catch (SQLException sqlEx) {
324 // don't wrap SQLExceptions
325 throw sqlEx;
326 } catch (IOException ioEx) {
327 long timeSinceLastReadMs = System.currentTimeMillis() - this.lastSuccessfulReadTimeMs;
328
329 String exceptionType = ioEx.getClass().getName();
330 String exceptionMessage = ioEx.getMessage();
331
332 exceptionMessage += "\n\nNested Stack Trace:\n";
333 exceptionMessage += Util.stackTraceToString(ioEx);
334
335 throw new java.sql.SQLException(
336 "IOException while retrieving next record in streaming result set."
337 + "(Check for deadlock "
338 + " or retrieval exceeding 'net_write_timeout' seconds. Last "
339 + "successful record read was " + timeSinceLastReadMs + " ms ago, and"
340 + "'net_write_timeout' is configured in the server as " + this.netWriteTimeoutMs
341 + " ms.) : "
342 + exceptionType + " message given: " + exceptionMessage, SQLError.SQL_STATE_GENERAL_ERROR);
343 } catch (Exception ex) {
344 String exceptionType = ex.getClass().getName();
345 String exceptionMessage = ex.getMessage();
346
347 exceptionMessage += "\n\nNested Stack Trace:\n";
348 exceptionMessage += Util.stackTraceToString(ex);
349
350 throw new java.sql.SQLException(
351 "Error retrieving record: Unexpected Exception: "
352 + exceptionType + " message given: " + exceptionMessage, SQLError.SQL_STATE_GENERAL_ERROR);
353 }
354 }
355
356 private void notSupported() throws SQLException {
357 throw new OperationNotSupportedException();
358 }
359
360 class OperationNotSupportedException extends SQLException {
361 OperationNotSupportedException() {
362 super("Operation not supported for streaming result sets", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
363 }
364 }
365 }