Mercurial > hg > monetdb-java
comparison src/main/java/org/monetdb/jdbc/MonetResultSet.java @ 391:f523727db392
Moved Java classes from packages starting with nl.cwi.monetdb.* to package org.monetdb.*
This naming complies to the Java Package Naming convention as MonetDB's main website is www.monetdb.org.
author | Martin van Dinther <martin.van.dinther@monetdbsolutions.com> |
---|---|
date | Thu, 12 Nov 2020 22:02:01 +0100 (2020-11-12) |
parents | src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java@cc472ea19b3f |
children | bf9f6b6ecf40 |
comparison
equal
deleted
inserted
replaced
390:6199e0be3c6e | 391:f523727db392 |
---|---|
1 /* | |
2 * This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
5 * | |
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2020 MonetDB B.V. | |
7 */ | |
8 | |
9 package org.monetdb.jdbc; | |
10 | |
11 import org.monetdb.mcl.parser.MCLParseException; | |
12 import org.monetdb.mcl.parser.TupleLineParser; | |
13 import java.io.InputStream; | |
14 import java.io.Reader; | |
15 import java.math.BigDecimal; | |
16 import java.net.URL; | |
17 import java.sql.Array; | |
18 import java.sql.Blob; | |
19 import java.sql.Clob; | |
20 import java.sql.Connection; | |
21 import java.sql.DatabaseMetaData; | |
22 import java.sql.NClob; | |
23 import java.sql.Ref; | |
24 import java.sql.ResultSet; | |
25 import java.sql.ResultSetMetaData; | |
26 import java.sql.RowId; | |
27 import java.sql.SQLData; | |
28 import java.sql.SQLDataException; | |
29 import java.sql.SQLException; | |
30 import java.sql.SQLFeatureNotSupportedException; | |
31 import java.sql.SQLInput; | |
32 import java.sql.SQLType; // new as of Java 1.8 | |
33 import java.sql.SQLWarning; | |
34 import java.sql.SQLXML; | |
35 import java.sql.Statement; | |
36 import java.sql.Time; | |
37 import java.sql.Timestamp; | |
38 import java.sql.Types; | |
39 import java.text.SimpleDateFormat; | |
40 import java.util.Calendar; | |
41 import java.util.Map; | |
42 import java.util.TimeZone; | |
43 | |
44 /** | |
45 * A ResultSet suitable for the MonetDB database. | |
46 * | |
47 * A table of data representing a database result set, which is usually | |
48 * generated by executing a statement that queries the database. | |
49 * | |
50 * A ResultSet object maintains a cursor pointing to its current row of data. | |
51 * Initially the cursor is positioned before the first row. The next method | |
52 * moves the cursor to the next row, and because it returns false when there | |
53 * are no more rows in the ResultSet object, it can be used in a while loop to | |
54 * iterate through the result set. | |
55 * | |
56 * The current state of this ResultSet is that it supports positioning in the | |
57 * result set, absolute and relative. A slight performance difference between | |
58 * FORWARD_ONLY or result sets scrollable in both directions can be noticed as | |
59 * for FORWARD_ONLY result sets the memory usage will be likely lower for large | |
60 * result sets. | |
61 * | |
62 * @author Fabian Groffen | |
63 * @author Martin van Dinther | |
64 * @version 0.9 | |
65 */ | |
66 public class MonetResultSet | |
67 extends MonetWrapper | |
68 implements ResultSet, AutoCloseable | |
69 { | |
70 static final int DEF_RESULTSETTYPE = ResultSet.TYPE_FORWARD_ONLY; | |
71 static final int DEF_FETCHDIRECTION = ResultSet.FETCH_FORWARD; | |
72 static final int DEF_CONCURRENCY = ResultSet.CONCUR_READ_ONLY; | |
73 static final int DEF_HOLDABILITY = ResultSet.HOLD_CURSORS_OVER_COMMIT; | |
74 | |
75 /** The parental Statement object */ | |
76 private final Statement statement; | |
77 /** A Header to retrieve lines from. Note: it will be null in case of a MonetVirtualResultSet ! */ | |
78 private final MonetConnection.ResultSetResponse header; | |
79 /** The names of the columns in this ResultSet */ | |
80 private final String[] columns; | |
81 /** The MonetDB types of the columns in this ResultSet */ | |
82 private final String[] types; | |
83 /** The JDBC SQL types of the columns in this ResultSet. The content will be derived from the MonetDB types[] */ | |
84 private final int[] JdbcSQLTypes; | |
85 | |
86 // the following have protected access modifier for the MonetVirtualResultSet subclass | |
87 // they are accessed from MonetVirtualResultSet.absolute() | |
88 /** The current line of the buffer split in columns */ | |
89 protected final TupleLineParser tlp; | |
90 /** The number of rows in this ResultSet */ | |
91 protected final long tupleCount; | |
92 /** The current position of the cursor for this ResultSet object */ | |
93 protected int curRow = 0; | |
94 | |
95 /** The type of this ResultSet (forward or scrollable) */ | |
96 private int type = DEF_RESULTSETTYPE; | |
97 /** The concurrency of this ResultSet (currently only read-only) */ | |
98 private int concurrency = DEF_CONCURRENCY; | |
99 /** The warnings for this ResultSet object */ | |
100 private SQLWarning warnings; | |
101 /** whether the last read field (via some getXyz() method) was NULL */ | |
102 private boolean lastReadWasNull = true; | |
103 /** to store the fetchsize set. */ | |
104 private int fetchSize; | |
105 | |
106 /** | |
107 * Main constructor backed by the given Header. | |
108 * | |
109 * @param statement the statement which created this ResultSet | |
110 * @param header a header containing the query, resultset type, etc. | |
111 * @throws IllegalArgumentException if called with null or invalid value for one of the arguments | |
112 */ | |
113 MonetResultSet( | |
114 final Statement statement, | |
115 final MonetConnection.ResultSetResponse header) | |
116 throws IllegalArgumentException | |
117 { | |
118 if (statement == null) { | |
119 throw new IllegalArgumentException("Statement may not be null!"); | |
120 } | |
121 if (header == null) { | |
122 throw new IllegalArgumentException("Header may not be null!"); | |
123 } | |
124 this.statement = statement; | |
125 this.header = header; | |
126 type = header.getRSType(); | |
127 concurrency = header.getRSConcur(); | |
128 /* the fetchSize used for this result set is the header's cacheSize */ | |
129 fetchSize = header.getCacheSize(); | |
130 | |
131 columns = header.getNames(); | |
132 types = header.getTypes(); | |
133 if (columns == null || types == null) { | |
134 throw new IllegalArgumentException("Missing Header metadata"); | |
135 } | |
136 if (columns.length != types.length) { | |
137 throw new IllegalArgumentException("Inconsistent Header metadata"); | |
138 } | |
139 tupleCount = header.tuplecount; | |
140 | |
141 // create result array | |
142 tlp = new TupleLineParser(columns.length); | |
143 | |
144 // for efficiency derive the JDBC SQL type codes from the types[] names once | |
145 JdbcSQLTypes = new int[types.length]; | |
146 populateJdbcSQLtypesArray(); | |
147 } | |
148 | |
149 /** | |
150 * Constructor used by MonetVirtualResultSet. | |
151 * DO NOT USE THIS CONSTRUCTOR IF YOU ARE NOT EXTENDING THIS OBJECT! | |
152 * | |
153 * @param statement the statement which created this ResultSet | |
154 * @param columns the column names | |
155 * @param types the column types | |
156 * @param results the number of rows in the ResultSet | |
157 * @throws IllegalArgumentException if called with null or invalid value for one of the arguments | |
158 */ | |
159 MonetResultSet( | |
160 final Statement statement, | |
161 final String[] columns, | |
162 final String[] types, | |
163 final int results) | |
164 throws IllegalArgumentException | |
165 { | |
166 if (statement == null || columns == null || types == null) { | |
167 throw new IllegalArgumentException("One of the given arguments is null"); | |
168 } | |
169 if (columns.length != types.length) { | |
170 throw new IllegalArgumentException("Given arrays are not the same size"); | |
171 } | |
172 if (results < 0) { | |
173 throw new IllegalArgumentException("Negative rowcount not allowed"); | |
174 } | |
175 | |
176 this.statement = statement; | |
177 header = null; | |
178 fetchSize = 0; | |
179 | |
180 this.columns = columns; | |
181 this.types = types; | |
182 tupleCount = results; | |
183 | |
184 tlp = new TupleLineParser(columns.length); | |
185 | |
186 // for efficiency derive the JDBC SQL type codes from the types[] names once | |
187 JdbcSQLTypes = new int[types.length]; | |
188 populateJdbcSQLtypesArray(); | |
189 } | |
190 | |
191 /** | |
192 * Internal utility method to fill the JdbcSQLTypes array with derivable values. | |
193 * By doing it once (in the constructor) we can avoid doing this in many getXyz() | |
194 * methods again and again thereby improving getXyz() method performance. | |
195 */ | |
196 private final void populateJdbcSQLtypesArray() { | |
197 MonetConnection connection = null; | |
198 try { | |
199 connection = (MonetConnection) statement.getConnection(); | |
200 } catch (SQLException se) { /* ignore it */ } | |
201 | |
202 for (int i = 0; i < types.length; i++) { | |
203 int javaSQLtype = MonetDriver.getJdbcSQLType(types[i]); | |
204 if (javaSQLtype == Types.CLOB) { | |
205 if (connection != null && connection.mapClobAsVarChar()) | |
206 javaSQLtype = Types.VARCHAR; | |
207 } else | |
208 if (javaSQLtype == Types.BLOB) { | |
209 if (connection != null && connection.mapBlobAsVarBinary()) | |
210 javaSQLtype = Types.VARBINARY; | |
211 } | |
212 JdbcSQLTypes[i] = javaSQLtype; | |
213 } | |
214 } | |
215 | |
216 | |
217 //== methods of interface ResultSet | |
218 | |
219 // Chapter 14.2.2 Sun JDBC 3.0 Specification | |
220 /** | |
221 * Moves the cursor to the given row number in this ResultSet object. | |
222 * | |
223 * If the row number is positive, the cursor moves to the given row number | |
224 * with respect to the beginning of the result set. The first row is row 1, | |
225 * the second is row 2, and so on. | |
226 * | |
227 * If the given row number is negative, the cursor moves to an absolute row | |
228 * position with respect to the end of the result set. For example, calling | |
229 * the method absolute(-1) positions the cursor on the last row; calling the | |
230 * method absolute(-2) moves the cursor to the next-to-last row, and so on. | |
231 * | |
232 * An attempt to position the cursor beyond the first/last row in the result | |
233 * set leaves the cursor before the first row or after the last row. | |
234 * Note: calling absolute(1) is the same as calling first(). Calling | |
235 * absolute(-1) is the same as calling last(). | |
236 * | |
237 * @param row the number of the row to which the cursor should move. A | |
238 * positive number indicates the row number counting from the | |
239 * beginning of the result set; a negative number indicates the row | |
240 * number counting from the end of the result set | |
241 * @return true if the cursor is on the result set; false otherwise | |
242 * @throws SQLException if a database access error occurs, or the result set | |
243 * type is TYPE_FORWARD_ONLY | |
244 */ | |
245 @Override | |
246 public boolean absolute(int row) throws SQLException { | |
247 checkNotClosed(); | |
248 if (row != curRow + 1 && type == TYPE_FORWARD_ONLY) | |
249 throw new SQLException("(Absolute) positioning not allowed on forward " + | |
250 " only result sets!", "M1M05"); | |
251 | |
252 // first calculate what the JDBC row is | |
253 if (row < 0) { | |
254 // calculate the negatives... | |
255 row = (int) tupleCount + row + 1; | |
256 } | |
257 // now place the row not farther than just before or after the result | |
258 if (row < 0) | |
259 row = 0; // before first | |
260 else if (row > tupleCount + 1) | |
261 row = (int) tupleCount + 1; // after last | |
262 | |
263 // store it | |
264 curRow = row; | |
265 | |
266 final String tmpLine = (header != null) ? header.getLine(row - 1) : null; | |
267 if (tmpLine == null) | |
268 return false; | |
269 | |
270 try { | |
271 tlp.parse(tmpLine); | |
272 } catch (MCLParseException e) { | |
273 throw new SQLException(e.getMessage(), "M0M10"); | |
274 } | |
275 | |
276 return true; | |
277 } | |
278 | |
279 /** | |
280 * Moves the cursor to the end of this ResultSet object, just after the last | |
281 * row. This method has no effect if the result set contains no rows. | |
282 * | |
283 * @throws SQLException if a database access error occurs or the result set | |
284 * type is TYPE_FORWARD_ONLY | |
285 */ | |
286 @Override | |
287 public void afterLast() throws SQLException { | |
288 absolute((int)tupleCount + 1); | |
289 } | |
290 | |
291 /** | |
292 * Moves the cursor to the front of this ResultSet object, just before the | |
293 * first row. This method has no effect if the result set contains no rows. | |
294 * | |
295 * @throws SQLException if a database access error occurs or the result set | |
296 * type is TYPE_FORWARD_ONLY | |
297 */ | |
298 @Override | |
299 public void beforeFirst() throws SQLException { | |
300 absolute(0); | |
301 } | |
302 | |
303 /** | |
304 * Clears all warnings reported for this ResultSet object. After a call to | |
305 * this method, the method getWarnings returns null until a new warning is | |
306 * reported for this ResultSet object. | |
307 */ | |
308 @Override | |
309 public void clearWarnings() { | |
310 warnings = null; | |
311 } | |
312 | |
313 /** | |
314 * Releases this ResultSet object's database (and JDBC) resources | |
315 * immediately instead of waiting for this to happen when it is | |
316 * automatically closed. | |
317 */ | |
318 @Override | |
319 public void close() { | |
320 if (header != null && !header.isClosed()) { | |
321 header.close(); | |
322 } | |
323 if (statement instanceof MonetStatement) | |
324 ((MonetStatement)statement).closeIfCompletion(); | |
325 } | |
326 | |
327 // Chapter 14.2.3 from Sun JDBC 3.0 specification | |
328 /** | |
329 * Maps the given ResultSet column name to its ResultSet column index. | |
330 * Column names supplied to getter methods are case insensitive. If a select | |
331 * list contains the same column more than once, the first instance of the | |
332 * column will be returned. | |
333 * | |
334 * @param columnLabel the name of the column | |
335 * @return the column index of the given column name | |
336 * @throws SQLException if the ResultSet object does not contain a column labeled columnLabel, | |
337 * a database access error occurs or this method is called on a closed result set | |
338 */ | |
339 @Override | |
340 public int findColumn(final String columnLabel) throws SQLException { | |
341 checkNotClosed(); | |
342 if (columnLabel != null) { | |
343 final int array_size = columns.length; | |
344 for (int i = 0; i < array_size; i++) { | |
345 if (columnLabel.equals(columns[i])) | |
346 return i + 1; | |
347 } | |
348 /* if an exact match did not succeed try a case insensitive match */ | |
349 for (int i = 0; i < array_size; i++) { | |
350 if (columnLabel.equalsIgnoreCase(columns[i])) | |
351 return i + 1; | |
352 } | |
353 } | |
354 throw new SQLException("No such column name: " + columnLabel, "M1M05"); | |
355 } | |
356 | |
357 /** | |
358 * Moves the cursor to the first row in this ResultSet object. | |
359 * | |
360 * @return true if the cursor is on a valid row; false if there are no rows | |
361 * in the result set | |
362 * @throws SQLException - if a database access error occurs or the result | |
363 * set type is TYPE_FORWARD_ONLY | |
364 */ | |
365 @Override | |
366 public boolean first() throws SQLException { | |
367 return absolute(1); | |
368 } | |
369 | |
370 @Override | |
371 public Array getArray(final int columnIndex) throws SQLException { | |
372 throw newSQLFeatureNotSupportedException("getArray"); | |
373 } | |
374 @Override | |
375 public Array getArray(final String columnLabel) throws SQLException { | |
376 throw newSQLFeatureNotSupportedException("getArray"); | |
377 } | |
378 | |
379 /* Mapi doesn't allow something for streams at the moment, thus all not implemented for now */ | |
380 @Override | |
381 public InputStream getAsciiStream(final int columnIndex) throws SQLException { | |
382 throw newSQLFeatureNotSupportedException("getAsciiStream"); | |
383 } | |
384 @Override | |
385 public InputStream getAsciiStream(final String columnLabel) throws SQLException { | |
386 throw newSQLFeatureNotSupportedException("getAsciiStream"); | |
387 } | |
388 | |
389 @Override | |
390 @Deprecated | |
391 public InputStream getUnicodeStream(int columnIndex) throws SQLException { | |
392 throw newSQLFeatureNotSupportedException("getUnicodeStream"); | |
393 } | |
394 @Override | |
395 @Deprecated | |
396 public InputStream getUnicodeStream(String columnLabel) throws SQLException { | |
397 throw newSQLFeatureNotSupportedException("getUnicodeStream"); | |
398 } | |
399 | |
400 /** | |
401 * Retrieves the value of the designated column in the current row | |
402 * of this ResultSet object as a stream of uninterpreted bytes. The | |
403 * value can then be read in chunks from the stream. This method is | |
404 * particularly suitable for retrieving large LONGVARBINARY values. | |
405 * | |
406 * Note: All the data in the returned stream must be read prior to | |
407 * getting the value of any other column. The next call to a getter | |
408 * method implicitly closes the stream. Also, a stream may return 0 | |
409 * when the method InputStream.available is called whether there is | |
410 * data available or not. | |
411 * | |
412 * @param columnIndex the first column is 1, the second is 2, ... | |
413 * @return a Java input stream that delivers the database column | |
414 * value as a stream of uninterpreted bytes; if the value is SQL | |
415 * NULL, the value returned is null | |
416 * @throws SQLException if the columnIndex is not valid; if a | |
417 * database access error occurs or this method is called on a closed result set | |
418 */ | |
419 @Override | |
420 public InputStream getBinaryStream(final int columnIndex) throws SQLException { | |
421 checkNotClosed(); | |
422 try { | |
423 switch (JdbcSQLTypes[columnIndex - 1]) { | |
424 case Types.BLOB: | |
425 final Blob blob = getBlob(columnIndex); | |
426 if (blob == null) | |
427 return null; | |
428 return blob.getBinaryStream(); | |
429 case Types.BINARY: | |
430 case Types.VARBINARY: | |
431 case Types.LONGVARBINARY: | |
432 final byte[] bte = getBytes(columnIndex); | |
433 if (bte == null) | |
434 return null; | |
435 return new java.io.ByteArrayInputStream(bte); | |
436 } | |
437 throw new SQLException("Cannot operate on " + types[columnIndex - 1] + " type", "M1M05"); | |
438 } catch (IndexOutOfBoundsException e) { | |
439 throw newSQLInvalidColumnIndexException(columnIndex); | |
440 } | |
441 } | |
442 | |
443 /** | |
444 * Retrieves the value of the designated column in the current row | |
445 * of this ResultSet object as a stream of uninterpreted bytes. The | |
446 * value can then be read in chunks from the stream. This method is | |
447 * particularly suitable for retrieving large LONGVARBINARY values. | |
448 * | |
449 * Note: All the data in the returned stream must be read prior to | |
450 * getting the value of any other column. The next call to a getter | |
451 * method implicitly closes the stream. Also, a stream may return 0 | |
452 * when the method available is called whether there is data | |
453 * available or not. | |
454 * | |
455 * @param columnLabel the label for the column specified with | |
456 * the SQL AS clause. If the SQL AS clause was not specified, then | |
457 * the label is the name of the column | |
458 * @return a Java input stream that delivers the database column | |
459 * value as a stream of uninterpreted bytes; if the value is SQL | |
460 * NULL, the result is null | |
461 * @throws SQLException if the columnLabel is not valid; if a | |
462 * database access error occurs or this method is called on a closed result set | |
463 */ | |
464 @Override | |
465 public InputStream getBinaryStream(final String columnLabel) throws SQLException { | |
466 return getBinaryStream(findColumn(columnLabel)); | |
467 } | |
468 | |
469 /** | |
470 * Retrieves the value of the designated column in the current row | |
471 * of this ResultSet object as a java.io.Reader object. | |
472 * | |
473 * @param columnIndex the first column is 1, the second is 2, ... | |
474 * @return a java.io.Reader object that contains the column value; | |
475 * if the value is SQL NULL, the value returned is null in | |
476 * the Java programming language. | |
477 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
478 */ | |
479 @Override | |
480 public Reader getCharacterStream(final int columnIndex) throws SQLException { | |
481 checkNotClosed(); | |
482 try { | |
483 final String val = tlp.values[columnIndex - 1]; | |
484 if (val == null) { | |
485 lastReadWasNull = true; | |
486 return null; | |
487 } | |
488 lastReadWasNull = false; | |
489 return new java.io.StringReader(val); | |
490 } catch (IndexOutOfBoundsException e) { | |
491 throw newSQLInvalidColumnIndexException(columnIndex); | |
492 } | |
493 } | |
494 | |
495 /** | |
496 * Retrieves the value of the designated column in the current row | |
497 * of this ResultSet object as a java.io.Reader object. | |
498 * | |
499 * @param columnLabel the name of the column | |
500 * @return a java.io.Reader object that contains the column value; | |
501 * if the value is SQL NULL, the value returned is null in | |
502 * the Java programming language. | |
503 * @throws SQLException if a database access error occurs | |
504 */ | |
505 @Override | |
506 public Reader getCharacterStream(final String columnLabel) throws SQLException { | |
507 return getCharacterStream(findColumn(columnLabel)); | |
508 } | |
509 | |
510 /** | |
511 * Retrieves the value of the designated column in the current row | |
512 * of this ResultSet object as a java.io.Reader object. It is | |
513 * intended for use when accessing NCHAR,NVARCHAR and LONGNVARCHAR | |
514 * columns. | |
515 * | |
516 * @param columnIndex the first column is 1, the second is 2, ... | |
517 * @return a java.io.Reader object that contains the column value; | |
518 * if the value is SQL NULL, the value returned is null in | |
519 * the Java programming language. | |
520 * @throws SQLException if a database access error occurs | |
521 */ | |
522 @Override | |
523 public Reader getNCharacterStream(final int columnIndex) throws SQLException { | |
524 return getCharacterStream(columnIndex); | |
525 } | |
526 | |
527 /** | |
528 * Retrieves the value of the designated column in the current row | |
529 * of this ResultSet object as a java.io.Reader object. It is | |
530 * intended for use when accessing NCHAR,NVARCHAR and LONGNVARCHAR | |
531 * columns. | |
532 * | |
533 * @param columnLabel the name of the column | |
534 * @return a java.io.Reader object that contains the column value; | |
535 * if the value is SQL NULL, the value returned is null in | |
536 * the Java programming language. | |
537 * @throws SQLException if a database access error occurs | |
538 */ | |
539 @Override | |
540 public Reader getNCharacterStream(final String columnLabel) throws SQLException { | |
541 return getCharacterStream(findColumn(columnLabel)); | |
542 } | |
543 | |
544 /** | |
545 * Retrieves the value of the designated column in the current row | |
546 * of this ResultSet object as a Blob object in the Java programming | |
547 * language. | |
548 * | |
549 * @param columnIndex the first column is 1, the second is 2, ... | |
550 * @return a Blob object representing the SQL BLOB value in the | |
551 * specified column | |
552 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
553 */ | |
554 @Override | |
555 public Blob getBlob(final int columnIndex) throws SQLException { | |
556 checkNotClosed(); | |
557 try { | |
558 final String val = tlp.values[columnIndex - 1]; | |
559 if (val == null) { | |
560 lastReadWasNull = true; | |
561 return null; | |
562 } | |
563 lastReadWasNull = false; | |
564 return new MonetBlob(val); | |
565 } catch (IndexOutOfBoundsException e) { | |
566 throw newSQLInvalidColumnIndexException(columnIndex); | |
567 } | |
568 } | |
569 | |
570 /** | |
571 * Retrieves the value of the designated column in the current row | |
572 * of this ResultSet object as a Blob object in the Java programming | |
573 * language. | |
574 * | |
575 * @param columnLabel the name of the column from which to retrieve | |
576 * the value | |
577 * @return a Blob object representing the SQL BLOB value in the | |
578 * specified column | |
579 * @throws SQLException if a database access error occurs | |
580 */ | |
581 @Override | |
582 public Blob getBlob(final String columnLabel) throws SQLException { | |
583 return getBlob(findColumn(columnLabel)); | |
584 } | |
585 | |
586 /** | |
587 * Retrieves the value of the designated column in the current row | |
588 * of this ResultSet object as a Clob object in the | |
589 * Java programming language. | |
590 * | |
591 * @param columnIndex the first column is 1, the second is 2, ... | |
592 * @return a Clob object representing the SQL CLOB value in the | |
593 * specified column | |
594 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
595 */ | |
596 @Override | |
597 public Clob getClob(final int columnIndex) throws SQLException { | |
598 checkNotClosed(); | |
599 try { | |
600 final String val = tlp.values[columnIndex - 1]; | |
601 if (val == null) { | |
602 lastReadWasNull = true; | |
603 return null; | |
604 } | |
605 lastReadWasNull = false; | |
606 return new MonetClob(val); | |
607 } catch (IndexOutOfBoundsException e) { | |
608 throw newSQLInvalidColumnIndexException(columnIndex); | |
609 } | |
610 } | |
611 | |
612 /** | |
613 * Retrieves the value of the designated column in the current row | |
614 * of this ResultSet object as a Clob object in the | |
615 * Java programming language. | |
616 * | |
617 * @param columnLabel the name of the column from which to retrieve | |
618 * the value | |
619 * @return a Clob object representing the SQL CLOB value in the | |
620 * specified column | |
621 * @throws SQLException if a database access error occurs | |
622 */ | |
623 @Override | |
624 public Clob getClob(final String columnLabel) throws SQLException { | |
625 return getClob(findColumn(columnLabel)); | |
626 } | |
627 | |
628 /** | |
629 * Retrieves the value of the designated column in the current row | |
630 * of this ResultSet object as a NClob object in the | |
631 * Java programming language. | |
632 * | |
633 * @param columnIndex the first column is 1, the second is 2, ... | |
634 * @return a NClob object representing the SQL NCLOB value in the | |
635 * specified column | |
636 * @throws SQLException if a database access error occurs | |
637 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
638 * not support this method | |
639 */ | |
640 @Override | |
641 public NClob getNClob(final int columnIndex) throws SQLException { | |
642 throw newSQLFeatureNotSupportedException("getNClob"); | |
643 } | |
644 | |
645 /** | |
646 * Retrieves the value of the designated column in the current row | |
647 * of this ResultSet object as a NClob object in the | |
648 * Java programming language. | |
649 * | |
650 * @param columnLabel the name of the column from which to retrieve | |
651 * the value | |
652 * @return a NClob object representing the SQL NCLOB value in the | |
653 * specified column | |
654 * @throws SQLException if a database access error occurs | |
655 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
656 * not support this method | |
657 */ | |
658 @Override | |
659 public NClob getNClob(final String columnLabel) throws SQLException { | |
660 throw newSQLFeatureNotSupportedException("getNClob"); | |
661 } | |
662 | |
663 /** | |
664 * Retrieves the value of the designated column in the current row of this | |
665 * ResultSet object as a java.math.BigDecimal with full precision. | |
666 * | |
667 * @param columnIndex the first column is 1, the second is 2, ... | |
668 * @return the column value (full precision); if the value is SQL NULL, | |
669 * the value returned is null in the Java programming language. | |
670 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
671 */ | |
672 @Override | |
673 public BigDecimal getBigDecimal(final int columnIndex) throws SQLException { | |
674 checkNotClosed(); | |
675 try { | |
676 final String val = tlp.values[columnIndex - 1]; | |
677 if (val == null) { | |
678 lastReadWasNull = true; | |
679 return null; | |
680 } | |
681 lastReadWasNull = false; | |
682 return new BigDecimal(val); | |
683 } catch (NumberFormatException e) { | |
684 throw newSQLNumberFormatException(e); | |
685 } catch (IndexOutOfBoundsException e) { | |
686 throw newSQLInvalidColumnIndexException(columnIndex); | |
687 } | |
688 } | |
689 | |
690 /** | |
691 * Retrieves the value of the designated column in the current row of this | |
692 * ResultSet object as a java.math.BigDecimal with full precision. | |
693 * | |
694 * @param columnIndex the first column is 1, the second is 2, ... | |
695 * @param scale the number of digits to the right of the decimal point | |
696 * @return the column value (full precision); if the value is SQL NULL, | |
697 * the value returned is null in the Java programming language. | |
698 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
699 */ | |
700 @Override | |
701 @Deprecated | |
702 public BigDecimal getBigDecimal(final int columnIndex, final int scale) | |
703 throws SQLException | |
704 { | |
705 checkNotClosed(); | |
706 try { | |
707 final String val = tlp.values[columnIndex - 1]; | |
708 if (val == null) { | |
709 lastReadWasNull = true; | |
710 return null; | |
711 } | |
712 lastReadWasNull = false; | |
713 return (new BigDecimal(val)).setScale(scale); | |
714 } catch (NumberFormatException e) { | |
715 throw newSQLNumberFormatException(e); | |
716 } catch (IndexOutOfBoundsException e) { | |
717 throw newSQLInvalidColumnIndexException(columnIndex); | |
718 } | |
719 } | |
720 | |
721 /** | |
722 * Retrieves the value of the designated column in the current row of this | |
723 * ResultSet object as a java.math.BigDecimal with full precision. | |
724 * | |
725 * @param columnLabel the SQL name of the column | |
726 * @return the column value (full precision); if the value is SQL NULL, | |
727 * the value returned is null in the Java programming language. | |
728 * @throws SQLException if a database access error occurs | |
729 */ | |
730 @Override | |
731 public BigDecimal getBigDecimal(final String columnLabel) throws SQLException { | |
732 return getBigDecimal(findColumn(columnLabel)); | |
733 } | |
734 | |
735 /** | |
736 * Retrieves the value of the designated column in the current row of this | |
737 * ResultSet object as a java.math.BigDecimal with full precision. | |
738 * | |
739 * @param columnLabel the SQL name of the column | |
740 * @param scale the number of digits to the right of the decimal point | |
741 * @return the column value (full precision); if the value is SQL NULL, | |
742 * the value returned is null in the Java programming language. | |
743 * @throws SQLException if a database access error occurs | |
744 */ | |
745 @Override | |
746 @Deprecated | |
747 public BigDecimal getBigDecimal(final String columnLabel, final int scale) | |
748 throws SQLException | |
749 { | |
750 return getBigDecimal(findColumn(columnLabel), scale); | |
751 } | |
752 | |
753 // See Sun JDBC Specification 3.0 Table B-6 | |
754 /** | |
755 * Retrieves the value of the designated column in the current row of this | |
756 * ResultSet object as a boolean in the Java programming language. | |
757 * | |
758 * @param columnIndex the first column is 1, the second is 2, ... | |
759 * @return the column value; if the value is SQL NULL, the value returned | |
760 * is false | |
761 * @throws SQLException if the columnIndex is not valid; if a database access error occurs | |
762 * or this method is called on a closed result set | |
763 */ | |
764 @Override | |
765 public boolean getBoolean(final int columnIndex) throws SQLException { | |
766 checkNotClosed(); | |
767 try { | |
768 final String val = tlp.values[columnIndex - 1]; | |
769 if (val == null) { | |
770 lastReadWasNull = true; | |
771 return false; // if the value is SQL NULL, the value returned is false | |
772 } | |
773 lastReadWasNull = false; | |
774 | |
775 // match common cases first | |
776 if ("false".equalsIgnoreCase(val) || "0".equals(val)) | |
777 return false; | |
778 if ("true".equalsIgnoreCase(val) || "1".equals(val)) | |
779 return true; | |
780 | |
781 // match type specific values | |
782 switch (JdbcSQLTypes[columnIndex - 1]) { | |
783 case Types.BOOLEAN: | |
784 case Types.CHAR: | |
785 case Types.VARCHAR: | |
786 case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness | |
787 case Types.CLOB: | |
788 // check if string value equals "true" (case insensitive) or not | |
789 return Boolean.parseBoolean(val); | |
790 case Types.TINYINT: | |
791 case Types.SMALLINT: | |
792 case Types.INTEGER: | |
793 if (getInt(columnIndex) == 0) { | |
794 return false; | |
795 } | |
796 return true; | |
797 case Types.BIGINT: | |
798 if (getLong(columnIndex) == 0L) { | |
799 return false; | |
800 } | |
801 return true; | |
802 case Types.DOUBLE: | |
803 case Types.FLOAT: | |
804 case Types.REAL: | |
805 if (getDouble(columnIndex) == 0.0) { | |
806 return false; | |
807 } | |
808 return true; | |
809 case Types.DECIMAL: | |
810 case Types.NUMERIC: | |
811 if (getBigDecimal(columnIndex).compareTo(BigDecimal.ZERO) == 0) { | |
812 return false; | |
813 } | |
814 return true; | |
815 default: | |
816 throw new SQLException("Conversion from " + types[columnIndex - 1] + " to boolean type not supported", "M1M05"); | |
817 } | |
818 } catch (IndexOutOfBoundsException e) { | |
819 throw newSQLInvalidColumnIndexException(columnIndex); | |
820 } | |
821 } | |
822 | |
823 /** | |
824 * Retrieves the value of the designated column in the current row of this | |
825 * ResultSet object as a boolean in the Java programming language. | |
826 * | |
827 * @param columnLabel the SQL name of the column | |
828 * @return the column value; if the value is SQL NULL, the value returned | |
829 * is false | |
830 * @throws SQLException if the ResultSet object does not contain columnLabel | |
831 */ | |
832 @Override | |
833 public boolean getBoolean(final String columnLabel) throws SQLException { | |
834 return getBoolean(findColumn(columnLabel)); | |
835 } | |
836 | |
837 /** | |
838 * Retrieves the value of the designated column in the current row of this | |
839 * ResultSet object as a byte in the Java programming language. | |
840 * | |
841 * @param columnIndex the first column is 1, the second is 2, ... | |
842 * @return the column value; if the value is SQL NULL, the value returned | |
843 * is 0 | |
844 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
845 */ | |
846 @Override | |
847 public byte getByte(final int columnIndex) throws SQLException { | |
848 checkNotClosed(); | |
849 try { | |
850 final String val = tlp.values[columnIndex - 1]; | |
851 if (val == null) { | |
852 lastReadWasNull = true; | |
853 return (byte) 0; | |
854 } | |
855 lastReadWasNull = false; | |
856 return Byte.parseByte(val); | |
857 } catch (NumberFormatException e) { | |
858 throw newSQLNumberFormatException(e); | |
859 } catch (IndexOutOfBoundsException e) { | |
860 throw newSQLInvalidColumnIndexException(columnIndex); | |
861 } | |
862 } | |
863 | |
864 /** | |
865 * Retrieves the value of the designated column in the current row of this | |
866 * ResultSet object as a byte in the Java programming language. | |
867 * | |
868 * @param columnLabel the SQL name of the column | |
869 * @return the column value; if the value is SQL NULL, the value returned | |
870 * is 0 | |
871 * @throws SQLException if a database access error occurs | |
872 */ | |
873 @Override | |
874 public byte getByte(final String columnLabel) throws SQLException { | |
875 return getByte(findColumn(columnLabel)); | |
876 } | |
877 | |
878 /** | |
879 * Retrieves the value of the designated column in the current row of this | |
880 * ResultSet object as a byte array in the Java programming language. The | |
881 * bytes represent the raw values returned by the driver. | |
882 * | |
883 * @param columnIndex the first column is 1, the second is 2, ... | |
884 * @return the column value; if the value is SQL NULL, the value returned | |
885 * is null | |
886 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
887 */ | |
888 @Override | |
889 public byte[] getBytes(final int columnIndex) throws SQLException { | |
890 checkNotClosed(); | |
891 try { | |
892 final String val = tlp.values[columnIndex - 1]; | |
893 if (val == null) { | |
894 lastReadWasNull = true; | |
895 return null; | |
896 } | |
897 lastReadWasNull = false; | |
898 | |
899 // According to Table B-6, getBytes() only operates on BINARY types | |
900 switch (JdbcSQLTypes[columnIndex - 1]) { | |
901 case Types.BLOB: | |
902 case Types.BINARY: | |
903 case Types.VARBINARY: | |
904 case Types.LONGVARBINARY: | |
905 return MonetBlob.hexStrToByteArray(val); | |
906 default: | |
907 throw new SQLException("Cannot operate on " + types[columnIndex - 1] + " type", "M1M05"); | |
908 } | |
909 } catch (NumberFormatException e) { | |
910 throw newSQLNumberFormatException(e); | |
911 } catch (IndexOutOfBoundsException e) { | |
912 throw newSQLInvalidColumnIndexException(columnIndex); | |
913 } | |
914 } | |
915 | |
916 /** | |
917 * Retrieves the value of the designated column in the current row of this | |
918 * ResultSet object as a byte array in the Java programming language. The | |
919 * bytes represent the raw values returned by the driver. | |
920 * | |
921 * NOTE: Since the mapi protocol is ASCII-based, this method only returns | |
922 * Java byte representations of Strings, which is nothing more than | |
923 * an encoding into a sequence of bytes using the platform's default | |
924 * charset. | |
925 * | |
926 * @param columnLabel the SQL name of the column | |
927 * @return the column value; if the value is SQL NULL, the value returned | |
928 * is null | |
929 * @throws SQLException if a database access error occurs | |
930 */ | |
931 @Override | |
932 public byte[] getBytes(final String columnLabel) throws SQLException { | |
933 return getBytes(findColumn(columnLabel)); | |
934 } | |
935 | |
936 /** | |
937 * Retrieves the concurrency mode of this ResultSet object. The concurrency | |
938 * used is determined by the Statement object that created the result set. | |
939 * | |
940 * NOTE: MonetDB only supports read-only result sets, and will always return | |
941 * ResultSet.CONCUR_READ_ONLY | |
942 * | |
943 * @return the concurrency type, either ResultSet.CONCUR_READ_ONLY or | |
944 * ResultSet.CONCUR_UPDATABLE | |
945 */ | |
946 @Override | |
947 public int getConcurrency() { | |
948 return concurrency; | |
949 } | |
950 | |
951 /** | |
952 * Retrieves the name of the SQL cursor used by this ResultSet object. | |
953 * In SQL, a result table is retrieved through a cursor that is named. | |
954 * For MonetDB this is the header.id returned in a resultset header. The | |
955 * current row of a result set can be updated or deleted using a positioned | |
956 * update/delete statement that references the cursor name. To insure that | |
957 * the cursor has the proper isolation level to support update, the | |
958 * cursor's SELECT statement should be of the form SELECT FOR UPDATE. If | |
959 * FOR UPDATE is omitted, the positioned updates may fail. | |
960 * | |
961 * The JDBC API supports this SQL feature by providing the name of the SQL | |
962 * cursor used by a ResultSet object. The current row of a ResultSet object | |
963 * is also the current row of this SQL cursor. | |
964 * | |
965 * Note: If positioned update is not supported, a SQLException is thrown. | |
966 * MonetDB currently doesn't support updates, so the SQLException is | |
967 * thrown for now. | |
968 * | |
969 * @return the SQL name for this ResultSet object's cursor | |
970 * @throws SQLException if a database access error occurs | |
971 */ | |
972 @Override | |
973 public String getCursorName() throws SQLException { | |
974 throw new SQLException("Positioned updates not supported for this " + | |
975 "cursor (" + (header != null ? header.id : "") + ")", "0AM21"); | |
976 } | |
977 | |
978 /** | |
979 * Retrieves the value of the designated column in the current row of this | |
980 * ResultSet object as a double in the Java programming language. | |
981 * | |
982 * @param columnIndex the first column is 1, the second is 2, ... | |
983 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
984 * @throws SQLException if there is no such column or this method is called on a closed result set | |
985 */ | |
986 @Override | |
987 public double getDouble(final int columnIndex) throws SQLException { | |
988 checkNotClosed(); | |
989 try { | |
990 final String val = tlp.values[columnIndex - 1]; | |
991 if (val == null) { | |
992 lastReadWasNull = true; | |
993 return 0; | |
994 } | |
995 lastReadWasNull = false; | |
996 return Double.parseDouble(val); | |
997 } catch (NumberFormatException e) { | |
998 throw newSQLNumberFormatException(e); | |
999 } catch (IndexOutOfBoundsException e) { | |
1000 throw newSQLInvalidColumnIndexException(columnIndex); | |
1001 } | |
1002 } | |
1003 | |
1004 /** | |
1005 * Retrieves the value of the designated column in the current row of this | |
1006 * ResultSet object as a double in the Java programming language. | |
1007 * | |
1008 * @param columnLabel the SQL name of the column | |
1009 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1010 * @throws SQLException if the ResultSet object does not contain columnLabel | |
1011 */ | |
1012 @Override | |
1013 public double getDouble(final String columnLabel) throws SQLException { | |
1014 return getDouble(findColumn(columnLabel)); | |
1015 } | |
1016 | |
1017 /** | |
1018 * Retrieves the holdability of this ResultSet object. | |
1019 * | |
1020 * @return either ResultSet.HOLD_CURSORS_OVER_COMMIT or | |
1021 * ResultSet.CLOSE_CURSORS_AT_COMMIT | |
1022 * @throws SQLException if a database access error occurs | |
1023 */ | |
1024 @Override | |
1025 public int getHoldability() throws SQLException { | |
1026 return getStatement().getConnection().getHoldability(); | |
1027 } | |
1028 | |
1029 /** | |
1030 * Retrieves the fetch direction for this ResultSet object. | |
1031 * | |
1032 * @return the current fetch direction for this ResultSet object | |
1033 */ | |
1034 @Override | |
1035 public int getFetchDirection() { | |
1036 return ResultSet.FETCH_FORWARD; | |
1037 } | |
1038 | |
1039 /** | |
1040 * Gives a hint as to the direction in which the rows in this ResultSet | |
1041 * object will be processed. The initial value is determined by the | |
1042 * Statement object that produced this ResultSet object. | |
1043 * The fetch direction may be changed at any time. | |
1044 * | |
1045 * @param direction - an int specifying the suggested fetch direction; | |
1046 * one of ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, or ResultSet.FETCH_UNKNOWN | |
1047 */ | |
1048 @Override | |
1049 public void setFetchDirection(final int direction) throws SQLException { | |
1050 switch (direction) { | |
1051 case ResultSet.FETCH_FORWARD: | |
1052 break; | |
1053 case ResultSet.FETCH_REVERSE: | |
1054 case ResultSet.FETCH_UNKNOWN: | |
1055 throw new SQLException("Not supported direction " + direction, "0A000"); | |
1056 default: | |
1057 throw new SQLException("Illegal direction: " + direction, "M1M05"); | |
1058 } | |
1059 } | |
1060 | |
1061 /** | |
1062 * Retrieves the fetch size for this ResultSet object. | |
1063 * | |
1064 * @return the current fetch size for this ResultSet object | |
1065 * @throws SQLException if a database access error occurs | |
1066 */ | |
1067 @Override | |
1068 public int getFetchSize() throws SQLException { | |
1069 return fetchSize; | |
1070 } | |
1071 | |
1072 /** | |
1073 * Gives the JDBC driver a hint as to the number of rows that should be | |
1074 * fetched from the database when more rows are needed. In MonetDB, this is | |
1075 * actually a no-op, because even before a MonetResultSet object is | |
1076 * created, the fetch size is already determined in the | |
1077 * MonetConnection.ResultSetResponse passed to its constructor. Since all | |
1078 * data blocks for this whole result set are already allocated in | |
1079 * MonetConnection.ResultSetResponse, it is too complicated and error-prone | |
1080 * to still change the fetchSize here. If one really needs to overwrite | |
1081 * the default fetchSize, please use MonetStatement.setFetchSize() instead. | |
1082 * | |
1083 * @param rows the number of rows to fetch | |
1084 * @throws SQLException if the condition 0 <= rows is not satisfied | |
1085 */ | |
1086 @Override | |
1087 public void setFetchSize(final int rows) throws SQLException { | |
1088 if (rows >= 0) { | |
1089 fetchSize = rows; | |
1090 } else { | |
1091 throw new SQLException("Illegal fetch size value: " + rows, "M1M05"); | |
1092 } | |
1093 } | |
1094 | |
1095 /** | |
1096 * Retrieves the value of the designated column in the current row of this | |
1097 * ResultSet object as a float in the Java programming language. | |
1098 * | |
1099 * @param columnIndex the first column is 1, the second is 2, ... | |
1100 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1101 * @throws SQLException if there is no such column or this method is called on a closed result set | |
1102 */ | |
1103 @Override | |
1104 public float getFloat(final int columnIndex) throws SQLException { | |
1105 checkNotClosed(); | |
1106 try { | |
1107 final String val = tlp.values[columnIndex - 1]; | |
1108 if (val == null) { | |
1109 lastReadWasNull = true; | |
1110 return 0; | |
1111 } | |
1112 lastReadWasNull = false; | |
1113 return Float.parseFloat(val); | |
1114 } catch (NumberFormatException e) { | |
1115 throw newSQLNumberFormatException(e); | |
1116 } catch (IndexOutOfBoundsException e) { | |
1117 throw newSQLInvalidColumnIndexException(columnIndex); | |
1118 } | |
1119 } | |
1120 | |
1121 /** | |
1122 * Retrieves the value of the designated column in the current row of this | |
1123 * ResultSet object as a float in the Java programming language. | |
1124 * | |
1125 * @param columnLabel the SQL name of the column | |
1126 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1127 * @throws SQLException if the ResultSet object does not contain columnLabel | |
1128 */ | |
1129 @Override | |
1130 public float getFloat(final String columnLabel) throws SQLException { | |
1131 return getFloat(findColumn(columnLabel)); | |
1132 } | |
1133 | |
1134 /** | |
1135 * Retrieves the value of the designated column in the current row of this | |
1136 * ResultSet object as an int in the Java programming language. | |
1137 * | |
1138 * @param columnIndex the first column is 1, the second is 2, ... | |
1139 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1140 * @throws SQLException if there is no such column or this method is called on a closed result set | |
1141 */ | |
1142 @Override | |
1143 public int getInt(final int columnIndex) throws SQLException { | |
1144 checkNotClosed(); | |
1145 String val = ""; | |
1146 try { | |
1147 val = tlp.values[columnIndex - 1]; | |
1148 if (val == null) { | |
1149 lastReadWasNull = true; | |
1150 return 0; | |
1151 } | |
1152 lastReadWasNull = false; | |
1153 return Integer.parseInt(val); | |
1154 } catch (NumberFormatException e) { | |
1155 // The oid datatype values (as string) have a @0 suffix in the string value. | |
1156 // To allow succesful parsing and conversion to int, we need to remove the suffix first | |
1157 if ("oid".equals(types[columnIndex - 1])) { | |
1158 if (val.endsWith("@0")) { | |
1159 try { | |
1160 return Integer.parseInt(val.substring(0, val.length()-2)); | |
1161 } catch (NumberFormatException nfe) { | |
1162 throw newSQLNumberFormatException(nfe); | |
1163 } | |
1164 } | |
1165 } | |
1166 throw newSQLNumberFormatException(e); | |
1167 } catch (IndexOutOfBoundsException e) { | |
1168 throw newSQLInvalidColumnIndexException(columnIndex); | |
1169 } | |
1170 } | |
1171 | |
1172 /** | |
1173 * Retrieves the value of the designated column in the current row of this | |
1174 * ResultSet object as an int in the Java programming language. | |
1175 * | |
1176 * @param columnLabel the SQL name of the column | |
1177 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1178 * @throws SQLException if the ResultSet object does not contain columnLabel | |
1179 */ | |
1180 @Override | |
1181 public int getInt(final String columnLabel) throws SQLException { | |
1182 return getInt(findColumn(columnLabel)); | |
1183 } | |
1184 | |
1185 /** | |
1186 * Retrieves the value of the designated column in the current row of this | |
1187 * ResultSet object as a long in the Java programming language. | |
1188 * | |
1189 * @param columnIndex the first column is 1, the second is 2, ... | |
1190 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1191 * @throws SQLException if there is no such column or this method is called on a closed result set | |
1192 */ | |
1193 @Override | |
1194 public long getLong(final int columnIndex) throws SQLException { | |
1195 checkNotClosed(); | |
1196 String val = ""; | |
1197 try { | |
1198 val = tlp.values[columnIndex - 1]; | |
1199 if (val == null) { | |
1200 lastReadWasNull = true; | |
1201 return 0; | |
1202 } | |
1203 lastReadWasNull = false; | |
1204 return Long.parseLong(val); | |
1205 } catch (NumberFormatException e) { | |
1206 // The oid datatype values (as string) have a @0 suffix in the string value. | |
1207 // To allow succesful parsing and conversion to long, we need to remove the suffix first | |
1208 if ("oid".equals(types[columnIndex - 1])) { | |
1209 if (val.endsWith("@0")) { | |
1210 try { | |
1211 return Long.parseLong(val.substring(0, val.length()-2)); | |
1212 } catch (NumberFormatException nfe) { | |
1213 throw newSQLNumberFormatException(nfe); | |
1214 } | |
1215 } | |
1216 } | |
1217 throw newSQLNumberFormatException(e); | |
1218 } catch (IndexOutOfBoundsException e) { | |
1219 throw newSQLInvalidColumnIndexException(columnIndex); | |
1220 } | |
1221 } | |
1222 | |
1223 /** | |
1224 * Retrieves the value of the designated column in the current row of this | |
1225 * ResultSet object as a long in the Java programming language. | |
1226 * | |
1227 * @param columnLabel the SQL name of the column | |
1228 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
1229 * @throws SQLException if the ResultSet object does not contain columnLabel | |
1230 */ | |
1231 @Override | |
1232 public long getLong(final String columnLabel) throws SQLException { | |
1233 return getLong(findColumn(columnLabel)); | |
1234 } | |
1235 | |
1236 | |
1237 /* helper for the anonymous class inside getMetaData */ | |
1238 private abstract class rsmdw extends MonetWrapper implements ResultSetMetaData {} | |
1239 | |
1240 /** | |
1241 * Retrieves the number, types and properties of this ResultSet object's | |
1242 * columns. | |
1243 * | |
1244 * @return the description of this ResultSet object's columns | |
1245 */ | |
1246 @Override | |
1247 public ResultSetMetaData getMetaData() throws SQLException { | |
1248 // return inner class which implements the ResultSetMetaData interface | |
1249 return new rsmdw() { | |
1250 // for the more expensive methods (getPrecision(), getScale(), isNullable(), isAutoIncrement()), we | |
1251 // use caches to store precision, scale and isNullable values from getColumns() combined per fully qualified column. | |
1252 private final int array_size = columns.length + 1; // add 1 as in JDBC columns start from 1 (array from 0). | |
1253 private final boolean[] _is_fetched = new boolean[array_size]; | |
1254 private final int[] _precision = new int[array_size]; | |
1255 private final int[] _scale = new int[array_size]; | |
1256 private final int[] _isNullable = new int[array_size]; | |
1257 private final boolean[] _isAutoincrement = new boolean[array_size]; | |
1258 private final Connection conn = getStatement().getConnection(); | |
1259 private DatabaseMetaData dbmd = null; // it will be assigned at first need and reused for other columns | |
1260 | |
1261 /** | |
1262 * A private utility method to check validity of column index number | |
1263 * @throws an SQLDataException when invalid column index number | |
1264 */ | |
1265 private final void checkColumnIndexValidity(final int column) throws SQLDataException { | |
1266 if (column < 1 || column > columns.length) | |
1267 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1268 } | |
1269 | |
1270 /** | |
1271 * A private method to fetch the precision, scale, isNullable and isAutoincrement value for a fully qualified column. | |
1272 * As md.getColumns() is an expensive method we call it only once per column and store | |
1273 * the precision, scale, isNullable and isAutoincrement values in the above array caches. | |
1274 * Also we only call md.getColumns() when we have a non empty schema name and table name and column name. | |
1275 */ | |
1276 private final void fetchColumnInfo(final int column) throws SQLException | |
1277 { | |
1278 checkColumnIndexValidity(column); | |
1279 | |
1280 _is_fetched[column] = true; | |
1281 _precision[column] = 0; | |
1282 _scale[column] = 0; | |
1283 _isNullable[column] = columnNullableUnknown; | |
1284 _isAutoincrement[column] = false; | |
1285 | |
1286 if (dbmd == null) { | |
1287 // first time usage | |
1288 dbmd = conn.getMetaData(); | |
1289 if (dbmd == null) | |
1290 return; | |
1291 } | |
1292 | |
1293 // we will only call dbmd.getColumns() when we have a specific schema name and table name and column name | |
1294 final String schName = getSchemaName(column); | |
1295 if (schName != null && !schName.isEmpty()) { | |
1296 final String tblName = getTableName(column); | |
1297 if (tblName != null && !tblName.isEmpty()) { | |
1298 final String colName = getColumnName(column); | |
1299 if (colName != null && !colName.isEmpty()) { | |
1300 // for precision, scale, isNullable and isAutoincrement we query the information from data dictionary | |
1301 final ResultSet colInfo = dbmd.getColumns(null, schName, tblName, colName); | |
1302 if (colInfo != null) { | |
1303 // we expect exactly one row in the resultset | |
1304 if (colInfo.next()) { | |
1305 _precision[column] = colInfo.getInt(7); // col 7 is "COLUMN_SIZE" | |
1306 _scale[column] = colInfo.getInt(9); // col 9 is "DECIMAL_DIGITS" | |
1307 _isNullable[column] = colInfo.getInt(11); // col 11 is "NULLABLE" | |
1308 final String strVal = colInfo.getString(23); // col 23 is "IS_AUTOINCREMENT" | |
1309 if (strVal != null && "YES".equals(strVal)) | |
1310 _isAutoincrement[column] = true; | |
1311 } | |
1312 colInfo.close(); // close the resultset to release resources | |
1313 } | |
1314 } | |
1315 } | |
1316 } | |
1317 } | |
1318 | |
1319 /** | |
1320 * Returns the number of columns in this ResultSet object. | |
1321 * | |
1322 * @return the number of columns | |
1323 */ | |
1324 @Override | |
1325 public int getColumnCount() { | |
1326 return columns.length; | |
1327 } | |
1328 | |
1329 /** | |
1330 * Indicates whether the designated column is automatically numbered. | |
1331 * | |
1332 * This method is currently very expensive for BIGINT, | |
1333 * INTEGER, SMALLINT and TINYINT result column types | |
1334 * as it needs to retrieve the information from the | |
1335 * database using an SQL meta data query. | |
1336 * | |
1337 * @param column the first column is 1, the second is 2, ... | |
1338 * @return true if so; false otherwise | |
1339 * @throws SQLException if a database access error occurs | |
1340 */ | |
1341 @Override | |
1342 public boolean isAutoIncrement(final int column) throws SQLException { | |
1343 // only few integer types can be auto incrementable in MonetDB | |
1344 // see: https://www.monetdb.org/Documentation/SQLReference/DataTypes/SerialDatatypes | |
1345 switch (getColumnType(column)) { | |
1346 case Types.BIGINT: | |
1347 case Types.INTEGER: | |
1348 case Types.SMALLINT: | |
1349 case Types.TINYINT: | |
1350 try { | |
1351 if (_is_fetched[column] != true) { | |
1352 fetchColumnInfo(column); | |
1353 } | |
1354 return _isAutoincrement[column]; | |
1355 } catch (IndexOutOfBoundsException e) { | |
1356 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1357 } | |
1358 } | |
1359 | |
1360 return false; | |
1361 } | |
1362 | |
1363 /** | |
1364 * Indicates whether a column's case matters. | |
1365 * | |
1366 * @param column the first column is 1, the second is 2, ... | |
1367 * @return true for all character string columns else false | |
1368 */ | |
1369 @Override | |
1370 public boolean isCaseSensitive(final int column) throws SQLException { | |
1371 switch (getColumnType(column)) { | |
1372 case Types.CHAR: | |
1373 case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness | |
1374 case Types.CLOB: | |
1375 return true; | |
1376 case Types.VARCHAR: | |
1377 final String monettype = getColumnTypeName(column); | |
1378 if (monettype != null && monettype.length() == 4) { | |
1379 // data of type inet or uuid is not case sensitive | |
1380 if ("inet".equals(monettype) | |
1381 || "uuid".equals(monettype)) | |
1382 return false; | |
1383 } | |
1384 return true; | |
1385 } | |
1386 | |
1387 return false; | |
1388 } | |
1389 | |
1390 /** | |
1391 * Indicates whether the designated column can be used in a | |
1392 * where clause. | |
1393 * It is unknown to me what kind ot columns they regard to, | |
1394 * as I think all columns are useable in a where clause. | |
1395 * Returning true for all here, for the time being. | |
1396 * Possible thought; maybe they want to know here if it's a | |
1397 * real column existing in a table or not... | |
1398 * | |
1399 * @param column the first column is 1, the second is 2, ... | |
1400 * @return true | |
1401 */ | |
1402 @Override | |
1403 public boolean isSearchable(final int column) throws SQLException { | |
1404 checkColumnIndexValidity(column); | |
1405 return true; | |
1406 } | |
1407 | |
1408 /** | |
1409 * Indicates whether the designated column is a cash value. | |
1410 * From the MonetDB database perspective it is by definition | |
1411 * unknown whether the value is a currency, because there are | |
1412 * no currency datatypes such as MONEY. With this knowledge | |
1413 * we can always return false here. | |
1414 * | |
1415 * @param column the first column is 1, the second is 2, ... | |
1416 * @return false | |
1417 */ | |
1418 @Override | |
1419 public boolean isCurrency(final int column) throws SQLException { | |
1420 checkColumnIndexValidity(column); | |
1421 return false; | |
1422 } | |
1423 | |
1424 /** | |
1425 * Indicates whether values in the designated column are signed | |
1426 * numbers. | |
1427 * Within MonetDB all numeric types (except oid and ptr) are signed. | |
1428 * | |
1429 * @param column the first column is 1, the second is 2, ... | |
1430 * @return true if so; false otherwise | |
1431 */ | |
1432 @Override | |
1433 public boolean isSigned(final int column) throws SQLException { | |
1434 // we can hardcode this, based on the colum type | |
1435 switch (getColumnType(column)) { | |
1436 case Types.TINYINT: | |
1437 case Types.SMALLINT: | |
1438 case Types.INTEGER: | |
1439 case Types.REAL: | |
1440 case Types.FLOAT: | |
1441 case Types.DOUBLE: | |
1442 case Types.DECIMAL: | |
1443 case Types.NUMERIC: | |
1444 return true; | |
1445 case Types.BIGINT: | |
1446 final String monettype = getColumnTypeName(column); | |
1447 if (monettype != null && monettype.length() == 3) { | |
1448 // data of type oid or ptr is not signed | |
1449 if ("oid".equals(monettype) | |
1450 || "ptr".equals(monettype)) | |
1451 return false; | |
1452 } | |
1453 return true; | |
1454 // All other types should return false | |
1455 // case Types.BOOLEAN: | |
1456 // case Types.DATE: // can year be negative? | |
1457 // case Types.TIME: // can time be negative? | |
1458 // case Types.TIME_WITH_TIMEZONE: | |
1459 // case Types.TIMESTAMP: // can year be negative? | |
1460 // case Types.TIMESTAMP_WITH_TIMEZONE: | |
1461 default: | |
1462 return false; | |
1463 } | |
1464 } | |
1465 | |
1466 /** | |
1467 * Indicates the designated column's normal maximum width in | |
1468 * characters. | |
1469 * | |
1470 * @param column the first column is 1, the second is 2, ... | |
1471 * @return the normal maximum number of characters allowed as the | |
1472 * width of the designated column | |
1473 * @throws SQLException if there is no such column | |
1474 */ | |
1475 @Override | |
1476 public int getColumnDisplaySize(final int column) throws SQLException { | |
1477 checkColumnIndexValidity(column); | |
1478 if (header != null) { | |
1479 try { | |
1480 return header.getColumnLengths()[column - 1]; | |
1481 } catch (IndexOutOfBoundsException e) { | |
1482 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1483 } | |
1484 } | |
1485 return 1; | |
1486 } | |
1487 | |
1488 /** | |
1489 * Get the designated column's schema name. | |
1490 * | |
1491 * @param column the first column is 1, the second is 2, ... | |
1492 * @return schema name or "" if not applicable | |
1493 * @throws SQLException if a database access error occurs | |
1494 */ | |
1495 @Override | |
1496 public String getSchemaName(final int column) throws SQLException { | |
1497 checkColumnIndexValidity(column); | |
1498 if (header != null) { | |
1499 // figure the name out | |
1500 try { | |
1501 final String schema = header.getTableNames()[column - 1]; | |
1502 if (schema != null) { | |
1503 final int dot = schema.indexOf('.'); | |
1504 return (dot >= 0) ? schema.substring(0, dot) : ""; | |
1505 } | |
1506 } catch (IndexOutOfBoundsException e) { | |
1507 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1508 } | |
1509 } | |
1510 return ""; | |
1511 } | |
1512 | |
1513 /** | |
1514 * Gets the designated column's table name. | |
1515 * | |
1516 * @param column the first column is 1, the second is 2, ... | |
1517 * @return table name or "" if not applicable | |
1518 */ | |
1519 @Override | |
1520 public String getTableName(final int column) throws SQLException { | |
1521 checkColumnIndexValidity(column); | |
1522 if (header != null) { | |
1523 // figure the name out | |
1524 try { | |
1525 final String table = header.getTableNames()[column - 1]; | |
1526 if (table != null) { | |
1527 final int dot = table.indexOf('.'); | |
1528 return (dot >= 0) ? table.substring(dot + 1) : table; | |
1529 } | |
1530 } catch (IndexOutOfBoundsException e) { | |
1531 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1532 } | |
1533 } | |
1534 return ""; | |
1535 } | |
1536 | |
1537 /** | |
1538 * Get the designated column's specified column size. | |
1539 * For numeric data, this is the maximum precision. | |
1540 * For character data, this is the length in characters. | |
1541 * For datetime datatypes, this is the length in characters | |
1542 * of the String representation (assuming the maximum | |
1543 * allowed precision of the fractional seconds component). | |
1544 * For binary data, this is the length in bytes. | |
1545 * For the ROWID datatype, this is the length in bytes. | |
1546 * 0 is returned for data types where the column size is not applicable. | |
1547 * | |
1548 * This method is currently very expensive for DECIMAL, NUMERIC | |
1549 * CHAR, VARCHAR, CLOB, BLOB, VARBINARY and BINARY result | |
1550 * column types as it needs to retrieve the information | |
1551 * from the database using an SQL meta data query. | |
1552 * | |
1553 * @param column the first column is 1, the second is 2, ... | |
1554 * @return precision | |
1555 * @throws SQLException if a database access error occurs | |
1556 */ | |
1557 @Override | |
1558 public int getPrecision(final int column) throws SQLException { | |
1559 final int tpe = getColumnType(column); | |
1560 switch (tpe) { | |
1561 case Types.BIGINT: | |
1562 return 19; | |
1563 case Types.INTEGER: | |
1564 return 10; | |
1565 case Types.SMALLINT: | |
1566 return 5; | |
1567 case Types.TINYINT: | |
1568 return 3; | |
1569 case Types.REAL: | |
1570 return 7; | |
1571 case Types.FLOAT: | |
1572 case Types.DOUBLE: | |
1573 return 15; | |
1574 | |
1575 case Types.DECIMAL: | |
1576 case Types.NUMERIC: | |
1577 // these data types do not have a fixed precision, max precision however is 38 | |
1578 // we need to fetch the defined precision with an SQL query ! | |
1579 case Types.CHAR: | |
1580 case Types.VARCHAR: | |
1581 case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness | |
1582 case Types.CLOB: | |
1583 case Types.BINARY: | |
1584 case Types.VARBINARY: | |
1585 case Types.BLOB: | |
1586 // these data types also do not have a fixed length | |
1587 try { | |
1588 if (_is_fetched[column] != true) { | |
1589 fetchColumnInfo(column); | |
1590 } | |
1591 if (_precision[column] == 0) { | |
1592 // apparently no precision or max length could be fetched | |
1593 // use columnDisplaySize() value as alternative | |
1594 _precision[column] = getColumnDisplaySize(column); | |
1595 if (tpe == Types.BLOB || tpe == Types.VARBINARY || tpe == Types.BINARY) | |
1596 // These expect number of bytes, not number of hex chars | |
1597 _precision[column] = (_precision[column] / 2) +1; | |
1598 } | |
1599 return _precision[column]; | |
1600 } catch (IndexOutOfBoundsException e) { | |
1601 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1602 } | |
1603 case Types.DATE: | |
1604 return 10; // 2020-10-08 | |
1605 case Types.TIME: | |
1606 return 15; // 21:51:34.399753 | |
1607 case Types.TIME_WITH_TIMEZONE: | |
1608 return 21; // 21:51:34.399753+02:00 | |
1609 case Types.TIMESTAMP: | |
1610 return 26; // 2020-10-08 21:51:34.399753 | |
1611 case Types.TIMESTAMP_WITH_TIMEZONE: | |
1612 return 32; // 2020-10-08 21:51:34.399753+02:00 | |
1613 case Types.BOOLEAN: | |
1614 return 1; | |
1615 default: | |
1616 // All other types should return 0 | |
1617 return 0; | |
1618 } | |
1619 } | |
1620 | |
1621 /** | |
1622 * Gets the designated column's number of digits to right of | |
1623 * the decimal point. | |
1624 * 0 is returned for data types where the scale is not applicable. | |
1625 * | |
1626 * This method is currently very expensive for DECIMAL and NUMERIC | |
1627 * result column types as it needs to retrieve the information | |
1628 * from the database using an SQL meta data query. | |
1629 * | |
1630 * @param column the first column is 1, the second is 2, ... | |
1631 * @return scale | |
1632 * @throws SQLException if a database access error occurs | |
1633 */ | |
1634 @Override | |
1635 public int getScale(final int column) throws SQLException { | |
1636 switch (getColumnType(column)) { | |
1637 case Types.DECIMAL: | |
1638 case Types.NUMERIC: | |
1639 // these data types may have a scale, max scale is 38 | |
1640 try { | |
1641 if (_is_fetched[column] != true) { | |
1642 fetchColumnInfo(column); | |
1643 } | |
1644 return _scale[column]; | |
1645 } catch (IndexOutOfBoundsException e) { | |
1646 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1647 } | |
1648 case Types.TIME: | |
1649 case Types.TIME_WITH_TIMEZONE: | |
1650 case Types.TIMESTAMP: | |
1651 case Types.TIMESTAMP_WITH_TIMEZONE: | |
1652 // support microseconds, so scale 6 | |
1653 return 6; // 21:51:34.399753 | |
1654 // All other types should return 0 | |
1655 // case Types.BIGINT: | |
1656 // case Types.INTEGER: | |
1657 // case Types.SMALLINT: | |
1658 // case Types.TINYINT: | |
1659 // case Types.REAL: | |
1660 // case Types.FLOAT: | |
1661 // case Types.DOUBLE: | |
1662 // case Types.CHAR: | |
1663 // case Types.VARCHAR: | |
1664 // case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness | |
1665 // case Types.CLOB: | |
1666 // case Types.BINARY: | |
1667 // case Types.VARBINARY: | |
1668 // case Types.BLOB: | |
1669 // case Types.DATE: | |
1670 // case Types.BOOLEAN: | |
1671 default: | |
1672 return 0; | |
1673 } | |
1674 } | |
1675 | |
1676 /** | |
1677 * Indicates the nullability of values in the designated column. | |
1678 * | |
1679 * This method is currently very expensive as it needs to | |
1680 * retrieve the information from the database using an SQL | |
1681 * meta data query (for each column). | |
1682 * | |
1683 * @param column the first column is 1, the second is 2, ... | |
1684 * @return the nullability status of the given column; one of | |
1685 * columnNoNulls, columnNullable or columnNullableUnknown | |
1686 * @throws SQLException if a database access error occurs | |
1687 */ | |
1688 @Override | |
1689 public int isNullable(final int column) throws SQLException { | |
1690 checkColumnIndexValidity(column); | |
1691 try { | |
1692 if (_is_fetched[column] != true) { | |
1693 fetchColumnInfo(column); | |
1694 } | |
1695 return _isNullable[column]; | |
1696 } catch (IndexOutOfBoundsException e) { | |
1697 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1698 } | |
1699 } | |
1700 | |
1701 /** | |
1702 * Gets the designated column's table's catalog name. | |
1703 * MonetDB does not support the catalog naming concept as in: catalog.schema.table naming scheme | |
1704 * | |
1705 * @param column the first column is 1, the second is 2, ... | |
1706 * @return the name of the catalog for the table in which the given | |
1707 * column appears or "" if not applicable | |
1708 */ | |
1709 @Override | |
1710 public String getCatalogName(final int column) throws SQLException { | |
1711 checkColumnIndexValidity(column); | |
1712 return null; // MonetDB does NOT support catalogs | |
1713 | |
1714 } | |
1715 | |
1716 /** | |
1717 * Indicates whether the designated column is definitely not | |
1718 * writable. MonetDB does not support cursor updates, so | |
1719 * nothing is writable. | |
1720 * | |
1721 * @param column the first column is 1, the second is 2, ... | |
1722 * @return true if so; false otherwise | |
1723 */ | |
1724 @Override | |
1725 public boolean isReadOnly(final int column) throws SQLException { | |
1726 checkColumnIndexValidity(column); | |
1727 return true; | |
1728 } | |
1729 | |
1730 /** | |
1731 * Indicates whether it is possible for a write on the | |
1732 * designated column to succeed. | |
1733 * | |
1734 * @param column the first column is 1, the second is 2, ... | |
1735 * @return true if so; false otherwise | |
1736 */ | |
1737 @Override | |
1738 public boolean isWritable(final int column) throws SQLException { | |
1739 checkColumnIndexValidity(column); | |
1740 return false; | |
1741 } | |
1742 | |
1743 /** | |
1744 * Indicates whether a write on the designated column will | |
1745 * definitely succeed. | |
1746 * | |
1747 * @param column the first column is 1, the second is 2, ... | |
1748 * @return true if so; false otherwise | |
1749 */ | |
1750 @Override | |
1751 public boolean isDefinitelyWritable(final int column) throws SQLException { | |
1752 checkColumnIndexValidity(column); | |
1753 return false; | |
1754 } | |
1755 | |
1756 /** | |
1757 * Returns the fully-qualified name of the Java class whose | |
1758 * instances are manufactured if the method | |
1759 * ResultSet.getObject is called to retrieve a value from | |
1760 * the column. ResultSet.getObject may return a subclass of | |
1761 * the class returned by this method. | |
1762 * | |
1763 * @param column the first column is 1, the second is 2, ... | |
1764 * @return the fully-qualified name of the class in the Java | |
1765 * programming language that would be used by the method | |
1766 * ResultSet.getObject to retrieve the value in the | |
1767 * specified column. This is the class name used for custom | |
1768 * mapping. | |
1769 * @throws SQLException if there is no such column | |
1770 */ | |
1771 @Override | |
1772 public String getColumnClassName(final int column) throws SQLException { | |
1773 checkColumnIndexValidity(column); | |
1774 try { | |
1775 final String MonetDBType = types[column - 1]; | |
1776 Class<?> type = null; | |
1777 if (conn != null) { | |
1778 final Map<String,Class<?>> map = conn.getTypeMap(); | |
1779 if (map != null && map.containsKey(MonetDBType)) { | |
1780 type = (Class)map.get(MonetDBType); | |
1781 } | |
1782 } | |
1783 if (type == null) { | |
1784 // fallback to the standard SQL type Class mappings | |
1785 type = getClassForType(JdbcSQLTypes[column - 1]); | |
1786 } | |
1787 if (type != null) { | |
1788 return type.getName(); | |
1789 } | |
1790 throw new SQLException("column type mapping null: " + MonetDBType, "M0M03"); | |
1791 } catch (IndexOutOfBoundsException e) { | |
1792 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1793 } | |
1794 } | |
1795 | |
1796 /** | |
1797 * Gets the designated column's suggested title for use in | |
1798 * printouts and displays. This is currently equal to | |
1799 * getColumnName(). | |
1800 * | |
1801 * @param column the first column is 1, the second is 2, ... | |
1802 * @return the suggested column title | |
1803 * @throws SQLException if there is no such column | |
1804 */ | |
1805 @Override | |
1806 public String getColumnLabel(final int column) throws SQLException { | |
1807 return getColumnName(column); | |
1808 } | |
1809 | |
1810 /** | |
1811 * Gets the designated column's name | |
1812 * | |
1813 * @param column the first column is 1, the second is 2, ... | |
1814 * @return the column name | |
1815 * @throws SQLException if there is no such column | |
1816 */ | |
1817 @Override | |
1818 public String getColumnName(final int column) throws SQLException { | |
1819 checkColumnIndexValidity(column); | |
1820 try { | |
1821 return columns[column - 1]; | |
1822 } catch (IndexOutOfBoundsException e) { | |
1823 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1824 } | |
1825 } | |
1826 | |
1827 /** | |
1828 * Retrieves the designated column's SQL type. | |
1829 * | |
1830 * @param column the first column is 1, the second is 2, ... | |
1831 * @return SQL type from java.sql.Types | |
1832 * @throws SQLException if there is no such column | |
1833 */ | |
1834 @Override | |
1835 public int getColumnType(final int column) throws SQLException { | |
1836 checkColumnIndexValidity(column); | |
1837 try { | |
1838 return JdbcSQLTypes[column - 1]; | |
1839 } catch (IndexOutOfBoundsException e) { | |
1840 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1841 } | |
1842 } | |
1843 | |
1844 /** | |
1845 * Retrieves the designated column's database-specific type name. | |
1846 * | |
1847 * @param column the first column is 1, the second is 2, ... | |
1848 * @return type name used by the database. If the column type is a | |
1849 * user-defined type, then a fully-qualified type name is | |
1850 * returned. | |
1851 * @throws SQLException if there is no such column | |
1852 */ | |
1853 @Override | |
1854 public String getColumnTypeName(final int column) throws SQLException { | |
1855 checkColumnIndexValidity(column); | |
1856 try { | |
1857 return types[column - 1]; | |
1858 } catch (IndexOutOfBoundsException e) { | |
1859 throw MonetResultSet.newSQLInvalidColumnIndexException(column); | |
1860 } | |
1861 } | |
1862 | |
1863 }; // end of new rsmdw() | |
1864 } // end of getMetaData() | |
1865 | |
1866 /** | |
1867 * Gets the value of the designated column in the current row of this | |
1868 * ResultSet object as an Object in the Java programming language. | |
1869 * | |
1870 * This method will return the value of the given column as a Java object. | |
1871 * The type of the Java object will be the default Java object type | |
1872 * corresponding to the column's SQL type, following the mapping for | |
1873 * built-in types specified in the JDBC specification. If the value is | |
1874 * an SQL NULL, the driver returns a Java null. | |
1875 * | |
1876 * This method may also be used to read database-specific abstract data | |
1877 * types. In the JDBC 2.0 API, the behavior of method getObject is extended | |
1878 * to materialize data of SQL user-defined types. When a column contains a | |
1879 * structured or distinct value, the behavior of this method is as if it | |
1880 * were a call to: getObject(columnIndex, this.getStatement().getConnection().getTypeMap()). | |
1881 * | |
1882 * @param columnIndex the first column is 1, the second is 2, ... | |
1883 * @return a java.lang.Object holding the column value or null | |
1884 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
1885 */ | |
1886 @Override | |
1887 public Object getObject(final int columnIndex) throws SQLException { | |
1888 // Many generic JDBC programs use getObject(colnr) to retrieve value objects from a resultset | |
1889 // For speed the implementation should be as fast as possible, so avoid method calls (by inlining code) where possible | |
1890 checkNotClosed(); | |
1891 | |
1892 final int JdbcType; | |
1893 final String val; | |
1894 try { | |
1895 val = tlp.values[columnIndex - 1]; | |
1896 if (val == null) { | |
1897 lastReadWasNull = true; | |
1898 return null; | |
1899 } | |
1900 lastReadWasNull = false; | |
1901 JdbcType = JdbcSQLTypes[columnIndex - 1]; | |
1902 } catch (IndexOutOfBoundsException e) { | |
1903 throw newSQLInvalidColumnIndexException(columnIndex); | |
1904 } | |
1905 | |
1906 switch(JdbcType) { | |
1907 case Types.TINYINT: | |
1908 case Types.SMALLINT: | |
1909 try { | |
1910 return Short.valueOf(val); | |
1911 } catch (NumberFormatException e) { | |
1912 return val; | |
1913 } | |
1914 case Types.INTEGER: | |
1915 try { | |
1916 return Integer.valueOf(val); | |
1917 } catch (NumberFormatException e) { | |
1918 return val; | |
1919 } | |
1920 case Types.BIGINT: | |
1921 try { | |
1922 return Long.valueOf(val); | |
1923 } catch (NumberFormatException e) { | |
1924 return val; | |
1925 } | |
1926 case Types.DOUBLE: | |
1927 case Types.FLOAT: | |
1928 try { | |
1929 return Double.valueOf(val); | |
1930 } catch (NumberFormatException e) { | |
1931 return val; | |
1932 } | |
1933 case Types.REAL: | |
1934 try { | |
1935 return Float.valueOf(val); | |
1936 } catch (NumberFormatException e) { | |
1937 return val; | |
1938 } | |
1939 case Types.DECIMAL: | |
1940 case Types.NUMERIC: | |
1941 try { | |
1942 return new BigDecimal(val); | |
1943 } catch (NumberFormatException e) { | |
1944 return val; | |
1945 } | |
1946 case Types.BOOLEAN: | |
1947 return Boolean.valueOf(val); | |
1948 case Types.VARCHAR: | |
1949 { | |
1950 // The MonetDB types: inet, json, url and uuid are all mapped to Types.VARCHAR in MonetDriver.typeMap | |
1951 // For these MonetDB types (except json, see comments below) we try to create objects of the corresponding class. | |
1952 final String MonetDBType = types[columnIndex - 1]; | |
1953 switch (MonetDBType.length()) { | |
1954 case 3: | |
1955 if ("url".equals(MonetDBType)) { | |
1956 try { | |
1957 final org.monetdb.jdbc.types.URL url_obj = new org.monetdb.jdbc.types.URL(); | |
1958 url_obj.fromString(val); | |
1959 return url_obj; | |
1960 } catch (Exception exc) { | |
1961 // ignore exception and just return the val String object | |
1962 return val; | |
1963 } | |
1964 } | |
1965 break; | |
1966 case 4: | |
1967 if ("inet".equals(MonetDBType)) { | |
1968 try { | |
1969 final org.monetdb.jdbc.types.INET inet_obj = new org.monetdb.jdbc.types.INET(); | |
1970 inet_obj.fromString(val); | |
1971 return inet_obj; | |
1972 } catch (Exception exc) { | |
1973 // ignore exception and just return the val String object | |
1974 return val; | |
1975 } | |
1976 } else | |
1977 if ("uuid".equals(MonetDBType)) { | |
1978 try { | |
1979 return java.util.UUID.fromString(val); | |
1980 } catch (IllegalArgumentException exc) { | |
1981 // ignore exception and just return the val String object | |
1982 return val; | |
1983 } | |
1984 // } else | |
1985 // if ("json".equals(MonetDBType)) { | |
1986 // There is no support for JSON in standard java class libraries. | |
1987 // Possibly we could use org.json.simple.JSONObject or other/faster libs | |
1988 // javax.json.Json is not released yet (see https://json-processing-spec.java.net/) | |
1989 // see also https://github.com/fabienrenaud/java-json-benchmark | |
1990 // Note that it would make our JDBC driver dependent of an external jar | |
1991 // and we don't want that so simply return it as String object | |
1992 // return val; | |
1993 } | |
1994 break; | |
1995 } | |
1996 return val; | |
1997 } | |
1998 case Types.CHAR: | |
1999 case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness | |
2000 return val; | |
2001 case Types.CLOB: | |
2002 return new MonetClob(val); | |
2003 case Types.BLOB: | |
2004 return new MonetBlob(val); | |
2005 case Types.DATE: | |
2006 return getDate(columnIndex, null); | |
2007 case Types.TIME: | |
2008 case Types.TIME_WITH_TIMEZONE: | |
2009 return getTime(columnIndex, null); | |
2010 case Types.TIMESTAMP: | |
2011 case Types.TIMESTAMP_WITH_TIMEZONE: | |
2012 return getTimestamp(columnIndex, null); | |
2013 case Types.BINARY: | |
2014 case Types.VARBINARY: | |
2015 case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY, it's here for completeness | |
2016 return getBytes(columnIndex); | |
2017 case Types.OTHER: | |
2018 default: | |
2019 // When we get here the column type is a non-standard JDBC SQL type, possibly a User Defined Type. | |
2020 // Just call getObject(int, Map) for those rare cases. | |
2021 return getObject(columnIndex, this.getStatement().getConnection().getTypeMap()); | |
2022 } | |
2023 } | |
2024 | |
2025 private final boolean classImplementsSQLData(final Class<?> cl) { | |
2026 final Class<?>[] cls = cl.getInterfaces(); | |
2027 for (int i = 0; i < cls.length; i++) { | |
2028 if (cls[i] == SQLData.class) | |
2029 return true; | |
2030 } | |
2031 return false; | |
2032 } | |
2033 | |
2034 /** | |
2035 * Gets the value of the designated column in the current row of this | |
2036 * ResultSet object as an Object in the Java programming language. | |
2037 * | |
2038 * This method will return the value of the given column as a Java object. | |
2039 * The type of the Java object will be the default Java object type corresponding | |
2040 * to the column's SQL type, following the mapping for built-in types specified | |
2041 * in the JDBC specification. | |
2042 * If the value is an SQL NULL, the driver returns a Java null. | |
2043 * | |
2044 * This method may also be used to read database-specific abstract data types. | |
2045 * In the JDBC 2.0 API, the behavior of method getObject is extended to | |
2046 * materialize data of SQL user-defined types. | |
2047 * | |
2048 * If Connection.getTypeMap does not throw a SQLFeatureNotSupportedException, then | |
2049 * when a column contains a structured or distinct value, the behavior of this | |
2050 * method is as if it were a call to: getObject(columnIndex, | |
2051 * this.getStatement().getConnection().getTypeMap()). | |
2052 * If Connection.getTypeMap does throw a SQLFeatureNotSupportedException, then | |
2053 * structured values are not supported, and distinct values are mapped to the | |
2054 * default Java class as determined by the underlying SQL type of the DISTINCT type. | |
2055 * | |
2056 * @param columnIndex the first column is 1, the second is 2, ... | |
2057 * @param map a java.util.Map object that contains the mapping from SQL | |
2058 * type names to classes in the Java programming language | |
2059 * @return an Object in the Java programming language representing the SQL value | |
2060 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
2061 */ | |
2062 @Override | |
2063 @SuppressWarnings("unchecked") | |
2064 public Object getObject(final int columnIndex, final Map<String,Class<?>> map) | |
2065 throws SQLException | |
2066 { | |
2067 checkNotClosed(); | |
2068 final String val; | |
2069 final String MonetDBtype; | |
2070 try { | |
2071 val = tlp.values[columnIndex - 1]; | |
2072 if (val == null) { | |
2073 lastReadWasNull = true; | |
2074 return null; | |
2075 } | |
2076 lastReadWasNull = false; | |
2077 MonetDBtype = types[columnIndex - 1]; | |
2078 } catch (IndexOutOfBoundsException e) { | |
2079 throw newSQLInvalidColumnIndexException(columnIndex); | |
2080 } | |
2081 | |
2082 Class<?> type = null; | |
2083 if (map != null && map.containsKey(MonetDBtype)) { | |
2084 type = map.get(MonetDBtype); | |
2085 } | |
2086 if (type == null) { | |
2087 // fallback to the standard SQL type Class mappings | |
2088 type = getClassForType(JdbcSQLTypes[columnIndex - 1]); | |
2089 } | |
2090 | |
2091 if (type == null || type == String.class) { | |
2092 return val; | |
2093 } else if (type == BigDecimal.class) { | |
2094 return getBigDecimal(columnIndex); | |
2095 } else if (type == Boolean.class) { | |
2096 return Boolean.valueOf(getBoolean(columnIndex)); | |
2097 } else if (type == Short.class) { | |
2098 return Short.valueOf(getShort(columnIndex)); | |
2099 } else if (type == Integer.class) { | |
2100 return Integer.valueOf(getInt(columnIndex)); | |
2101 } else if (type == Long.class) { | |
2102 return Long.valueOf(getLong(columnIndex)); | |
2103 } else if (type == Float.class) { | |
2104 return Float.valueOf(getFloat(columnIndex)); | |
2105 } else if (type == Double.class) { | |
2106 return Double.valueOf(getDouble(columnIndex)); | |
2107 } else if (type == byte[].class) { | |
2108 return getBytes(columnIndex); | |
2109 } else if (type == java.sql.Date.class) { | |
2110 return getDate(columnIndex, null); | |
2111 } else if (type == Time.class) { | |
2112 return getTime(columnIndex, null); | |
2113 } else if (type == Timestamp.class) { | |
2114 return getTimestamp(columnIndex, null); | |
2115 } else if (type == Clob.class) { | |
2116 return getClob(columnIndex); | |
2117 } else if (type == Blob.class) { | |
2118 return getBlob(columnIndex); | |
2119 } else if (classImplementsSQLData(type)) { | |
2120 final SQLData x; | |
2121 try { | |
2122 final java.lang.reflect.Constructor<? extends SQLData> ctor = | |
2123 ((Class)type).getConstructor(); | |
2124 x = ctor.newInstance(); | |
2125 } catch (NoSuchMethodException nsme) { | |
2126 throw new SQLException(nsme.getMessage(), "M0M27"); | |
2127 } catch (InstantiationException ie) { | |
2128 throw new SQLException(ie.getMessage(), "M0M27"); | |
2129 } catch (IllegalAccessException iae) { | |
2130 throw new SQLException(iae.getMessage(), "M0M27"); | |
2131 } catch (java.lang.reflect.InvocationTargetException ite) { | |
2132 throw new SQLException(ite.getMessage(), "M0M27"); | |
2133 } catch (SecurityException se) { | |
2134 throw new SQLException(se.getMessage(), "M0M27"); | |
2135 } | |
2136 final int colnum = columnIndex; | |
2137 final boolean valwasnull = wasNull(); | |
2138 final SQLInput input = new SQLInput() { | |
2139 @Override | |
2140 public String readString() throws SQLException { | |
2141 return getString(colnum); | |
2142 } | |
2143 | |
2144 @Override | |
2145 public boolean readBoolean() throws SQLException { | |
2146 return getBoolean(colnum); | |
2147 } | |
2148 | |
2149 @Override | |
2150 public byte readByte() throws SQLException { | |
2151 return getByte(colnum); | |
2152 } | |
2153 | |
2154 @Override | |
2155 public short readShort() throws SQLException { | |
2156 return getShort(colnum); | |
2157 } | |
2158 | |
2159 @Override | |
2160 public int readInt() throws SQLException { | |
2161 return getInt(colnum); | |
2162 } | |
2163 | |
2164 @Override | |
2165 public long readLong() throws SQLException { | |
2166 return getLong(colnum); | |
2167 } | |
2168 | |
2169 @Override | |
2170 public float readFloat() throws SQLException { | |
2171 return getFloat(colnum); | |
2172 } | |
2173 | |
2174 @Override | |
2175 public double readDouble() throws SQLException { | |
2176 return getDouble(colnum); | |
2177 } | |
2178 | |
2179 @Override | |
2180 public BigDecimal readBigDecimal() throws SQLException { | |
2181 return getBigDecimal(colnum); | |
2182 } | |
2183 | |
2184 @Override | |
2185 public byte[] readBytes() throws SQLException { | |
2186 return getBytes(colnum); | |
2187 } | |
2188 | |
2189 @Override | |
2190 public java.sql.Date readDate() throws SQLException { | |
2191 return getDate(colnum, null); | |
2192 } | |
2193 | |
2194 @Override | |
2195 public java.sql.Time readTime() throws SQLException { | |
2196 return getTime(colnum, null); | |
2197 } | |
2198 | |
2199 @Override | |
2200 public Timestamp readTimestamp() throws SQLException { | |
2201 return getTimestamp(colnum, null); | |
2202 } | |
2203 | |
2204 @Override | |
2205 public Reader readCharacterStream() throws SQLException { | |
2206 return getCharacterStream(colnum); | |
2207 } | |
2208 | |
2209 @Override | |
2210 public InputStream readAsciiStream() throws SQLException { | |
2211 return getAsciiStream(colnum); | |
2212 } | |
2213 | |
2214 @Override | |
2215 public InputStream readBinaryStream() throws SQLException { | |
2216 return getBinaryStream(colnum); | |
2217 } | |
2218 | |
2219 @Override | |
2220 public Object readObject() throws SQLException { | |
2221 return getObject(colnum); | |
2222 } | |
2223 | |
2224 @Override | |
2225 public Ref readRef() throws SQLException { | |
2226 return getRef(colnum); | |
2227 } | |
2228 | |
2229 @Override | |
2230 public Blob readBlob() throws SQLException { | |
2231 return getBlob(colnum); | |
2232 } | |
2233 | |
2234 @Override | |
2235 public Clob readClob() throws SQLException { | |
2236 return getClob(colnum); | |
2237 } | |
2238 | |
2239 @Override | |
2240 public Array readArray() throws SQLException { | |
2241 return getArray(colnum); | |
2242 } | |
2243 | |
2244 @Override | |
2245 public boolean wasNull() throws SQLException { | |
2246 return valwasnull; | |
2247 } | |
2248 | |
2249 @Override | |
2250 public URL readURL() throws SQLException { | |
2251 return getURL(colnum); | |
2252 } | |
2253 | |
2254 @Override | |
2255 public NClob readNClob() throws SQLException { | |
2256 return getNClob(colnum); | |
2257 } | |
2258 | |
2259 @Override | |
2260 public String readNString() throws SQLException { | |
2261 return getNString(colnum); | |
2262 } | |
2263 | |
2264 @Override | |
2265 public SQLXML readSQLXML() throws SQLException { | |
2266 return getSQLXML(colnum); | |
2267 } | |
2268 | |
2269 @Override | |
2270 public RowId readRowId() throws SQLException { | |
2271 return getRowId(colnum); | |
2272 } | |
2273 }; | |
2274 x.readSQL(input, MonetDBtype); | |
2275 return x; | |
2276 } else { | |
2277 return val; | |
2278 } | |
2279 } | |
2280 | |
2281 /** | |
2282 * Helper method to support the getObject and | |
2283 * ResultsetMetaData.getColumnClassName JDBC methods. | |
2284 * | |
2285 * @param type a value from java.sql.Types | |
2286 * @return a Class object from which an instance would be returned | |
2287 */ | |
2288 final static Class<?> getClassForType(final int type) { | |
2289 /** | |
2290 * This switch returns the types as objects according to table B-3 from | |
2291 * Oracle's JDBC specification 4.1 | |
2292 */ | |
2293 // keep this switch regarding the returned classes aligned with getObject(int, Map) ! | |
2294 switch(type) { | |
2295 case Types.CHAR: | |
2296 case Types.VARCHAR: | |
2297 case Types.LONGVARCHAR: | |
2298 return String.class; | |
2299 case Types.NUMERIC: | |
2300 case Types.DECIMAL: | |
2301 return BigDecimal.class; | |
2302 case Types.BOOLEAN: | |
2303 return Boolean.class; | |
2304 case Types.TINYINT: | |
2305 case Types.SMALLINT: | |
2306 return Short.class; | |
2307 case Types.INTEGER: | |
2308 return Integer.class; | |
2309 case Types.BIGINT: | |
2310 return Long.class; | |
2311 case Types.REAL: | |
2312 return Float.class; | |
2313 case Types.FLOAT: | |
2314 case Types.DOUBLE: | |
2315 return Double.class; | |
2316 case Types.BINARY: // MonetDB currently does not support these | |
2317 case Types.VARBINARY: // see treat_blob_as_binary property | |
2318 case Types.LONGVARBINARY: | |
2319 return byte[].class; | |
2320 case Types.DATE: | |
2321 return java.sql.Date.class; | |
2322 case Types.TIME: | |
2323 case Types.TIME_WITH_TIMEZONE: | |
2324 return Time.class; | |
2325 case Types.TIMESTAMP: | |
2326 case Types.TIMESTAMP_WITH_TIMEZONE: | |
2327 return Timestamp.class; | |
2328 case Types.CLOB: | |
2329 return Clob.class; | |
2330 case Types.BLOB: | |
2331 return Blob.class; | |
2332 | |
2333 // all the rest are currently not implemented and used | |
2334 default: | |
2335 return String.class; | |
2336 } | |
2337 } | |
2338 | |
2339 /** | |
2340 * Gets the value of the designated column in the current row of this | |
2341 * ResultSet object as an Object in the Java programming language. | |
2342 * | |
2343 * This method will return the value of the given column as a Java object. | |
2344 * The type of the Java object will be the default Java object type | |
2345 * corresponding to the column's SQL type, following the mapping for | |
2346 * built-in types specified in the JDBC specification. If the value is an | |
2347 * SQL NULL, the driver returns a Java null. | |
2348 * | |
2349 * This method may also be used to read database-specific abstract data | |
2350 * types. | |
2351 * | |
2352 * @param columnLabel the SQL name of the column | |
2353 * @return a java.lang.Object holding the column value | |
2354 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
2355 */ | |
2356 @Override | |
2357 public Object getObject(final String columnLabel) throws SQLException { | |
2358 return getObject(findColumn(columnLabel)); | |
2359 } | |
2360 | |
2361 /** | |
2362 * Retrieves the value of the designated column in the current row of this | |
2363 * ResultSet object as an Object in the Java programming language. If the | |
2364 * value is an SQL NULL, the driver returns a Java null. This method uses | |
2365 * the specified Map object for custom mapping if appropriate. | |
2366 * | |
2367 * @param columnLabel the name of the column from which to retrieve the value | |
2368 * @param map a java.util.Map object that contains the mapping from SQL | |
2369 * type names to classes in the Java programming language | |
2370 * @return an Object representing the SQL value in the specified column | |
2371 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
2372 */ | |
2373 @Override | |
2374 public Object getObject(final String columnLabel, final Map<String,Class<?>> map) throws SQLException { | |
2375 return getObject(findColumn(columnLabel), map); | |
2376 } | |
2377 | |
2378 @Override | |
2379 public Ref getRef(int columnIndex) throws SQLException { | |
2380 throw newSQLFeatureNotSupportedException("getRef"); | |
2381 } | |
2382 | |
2383 @Override | |
2384 public Ref getRef(final String columnLabel) throws SQLException { | |
2385 throw newSQLFeatureNotSupportedException("getRef"); | |
2386 } | |
2387 | |
2388 /** | |
2389 * Retrieves the current row number. The first row is number 1, the second | |
2390 * number 2, and so on. | |
2391 * | |
2392 * @return the current row number; 0 if there is no current row | |
2393 */ | |
2394 @Override | |
2395 public int getRow() { | |
2396 return curRow; | |
2397 } | |
2398 | |
2399 /** | |
2400 * Retrieves the value of the designated column in the current row | |
2401 * of this ResultSet object as a java.sql.RowId object in the Java | |
2402 * programming language. | |
2403 * | |
2404 * @param columnIndex the first column is 1, the second is 2, ... | |
2405 * @return the column value; if the value is SQL NULL, the value returned | |
2406 * is null | |
2407 * @throws SQLException if there is no such column | |
2408 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
2409 * not support this method | |
2410 */ | |
2411 @Override | |
2412 public RowId getRowId(final int columnIndex) throws SQLException { | |
2413 throw newSQLFeatureNotSupportedException("getRowId"); | |
2414 } | |
2415 | |
2416 /** | |
2417 * Retrieves the value of the designated column in the current row | |
2418 * of this ResultSet object as a java.sql.RowId object in the Java | |
2419 * programming language. | |
2420 * | |
2421 * @param columnLabel the SQL name of the column | |
2422 * @return the column value; if the value is SQL NULL, the value returned | |
2423 * is null | |
2424 * @throws SQLException if the ResultSet object does not contain columnLabel | |
2425 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
2426 * not support this method | |
2427 */ | |
2428 @Override | |
2429 public RowId getRowId(final String columnLabel) throws SQLException { | |
2430 throw newSQLFeatureNotSupportedException("getRowId"); | |
2431 } | |
2432 | |
2433 /** | |
2434 * Retrieves the value of the designated column in the current row of this | |
2435 * ResultSet object as a short in the Java programming language. | |
2436 * | |
2437 * @param columnIndex the first column is 1, the second is 2, ... | |
2438 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
2439 * @throws SQLException if there is no such column or this method is called on a closed result set | |
2440 */ | |
2441 @Override | |
2442 public short getShort(final int columnIndex) throws SQLException { | |
2443 checkNotClosed(); | |
2444 try { | |
2445 final String val = tlp.values[columnIndex - 1]; | |
2446 if (val == null) { | |
2447 lastReadWasNull = true; | |
2448 return 0; | |
2449 } | |
2450 lastReadWasNull = false; | |
2451 return Short.parseShort(val); | |
2452 } catch (NumberFormatException e) { | |
2453 throw newSQLNumberFormatException(e); | |
2454 } catch (IndexOutOfBoundsException e) { | |
2455 throw newSQLInvalidColumnIndexException(columnIndex); | |
2456 } | |
2457 } | |
2458 | |
2459 /** | |
2460 * Retrieves the value of the designated column in the current row of this | |
2461 * ResultSet object as a short in the Java programming language. | |
2462 * | |
2463 * @param columnLabel the SQL name of the column | |
2464 * @return the column value; if the value is SQL NULL, the value returned is 0 | |
2465 * @throws SQLException if the ResultSet object does not contain columnLabel | |
2466 */ | |
2467 @Override | |
2468 public short getShort(final String columnLabel) throws SQLException { | |
2469 return getShort(findColumn(columnLabel)); | |
2470 } | |
2471 | |
2472 /** | |
2473 * Retrieves the Statement object that produced this ResultSet object. | |
2474 * If the result set was generated some other way, such as by a | |
2475 * DatabaseMetaData method, this method may return null. | |
2476 * | |
2477 * In our implementation we always return a non-null object, see constructors. | |
2478 * Also from subclass MonetVirtualResultSet, see its constructor. | |
2479 * | |
2480 * @return the Statement object that produced this ResultSet object or | |
2481 * null if the result set was produced some other way | |
2482 */ | |
2483 @Override | |
2484 public Statement getStatement() { | |
2485 return statement; | |
2486 } | |
2487 | |
2488 /** | |
2489 * Retrieves the value of the designated column in the current row of this | |
2490 * ResultSet object as a String in the Java programming language. | |
2491 * | |
2492 * @param columnIndex the first column is 1, the second is 2, ... | |
2493 * @return the column value; if the value is SQL NULL, the value returned is null | |
2494 * @throws SQLException if there is no such column or this method is called on a closed result set | |
2495 */ | |
2496 @Override | |
2497 public String getString(final int columnIndex) throws SQLException { | |
2498 checkNotClosed(); | |
2499 try { | |
2500 final String val = tlp.values[columnIndex - 1]; | |
2501 if (val == null) { | |
2502 lastReadWasNull = true; | |
2503 return null; | |
2504 } | |
2505 lastReadWasNull = false; | |
2506 return val; | |
2507 } catch (IndexOutOfBoundsException e) { | |
2508 throw newSQLInvalidColumnIndexException(columnIndex); | |
2509 } | |
2510 } | |
2511 | |
2512 /** | |
2513 * Retrieves the value of the designated column in the current row of this | |
2514 * ResultSet object as a String in the Java programming language. | |
2515 * | |
2516 * @param columnLabel the SQL name of the column | |
2517 * @return the column value; if the value is SQL NULL, the value returned is null | |
2518 * @throws SQLException if the ResultSet object does not contain columnLabel | |
2519 */ | |
2520 @Override | |
2521 public String getString(final String columnLabel) throws SQLException { | |
2522 return getString(findColumn(columnLabel)); | |
2523 } | |
2524 | |
2525 /** | |
2526 * Retrieves the value of the designated column in the current row | |
2527 * of this ResultSet object as a String in the Java programming | |
2528 * language. It is intended for use when accessing NCHAR,NVARCHAR | |
2529 * and LONGNVARCHAR columns. | |
2530 * | |
2531 * @param columnIndex the first column is 1, the second is 2, ... | |
2532 * @return the column value; if the value is SQL NULL, the value returned is null | |
2533 * @throws SQLException if there is no such column | |
2534 */ | |
2535 @Override | |
2536 public String getNString(final int columnIndex) throws SQLException { | |
2537 return getString(columnIndex); | |
2538 } | |
2539 | |
2540 /** | |
2541 * Retrieves the value of the designated column in the current row | |
2542 * of this ResultSet object as a String in the Java programming | |
2543 * language. It is intended for use when accessing NCHAR,NVARCHAR | |
2544 * and LONGNVARCHAR columns. | |
2545 * | |
2546 * @param columnLabel the SQL name of the column | |
2547 * @return the column value; if the value is SQL NULL, the value returned is null | |
2548 * @throws SQLException if the ResultSet object does not contain columnLabel | |
2549 */ | |
2550 @Override | |
2551 public String getNString(final String columnLabel) throws SQLException { | |
2552 return getString(findColumn(columnLabel)); | |
2553 } | |
2554 | |
2555 /** | |
2556 * Retrieves the value of the designated column in the current row | |
2557 * of this ResultSet as a java.sql.SQLXML object in the Java | |
2558 * programming language. | |
2559 * | |
2560 * @param columnIndex the first column is 1, the second is 2, ... | |
2561 * @return a SQLXML object that maps an SQL XML value | |
2562 * @throws SQLException if a database access error occurs | |
2563 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
2564 * not support this method | |
2565 */ | |
2566 @Override | |
2567 public SQLXML getSQLXML(final int columnIndex) throws SQLException { | |
2568 throw newSQLFeatureNotSupportedException("getSQLXML"); | |
2569 } | |
2570 | |
2571 /** | |
2572 * Retrieves the value of the designated column in the current row | |
2573 * of this ResultSet as a java.sql.SQLXML object in the Java | |
2574 * programming language. | |
2575 * | |
2576 * @param columnLabel the label for the column specified with the SQL AS | |
2577 * clause. If the SQL AS clause was not specified, then the | |
2578 * label is the name of the column | |
2579 * @return a SQLXML object that maps an SQL XML value | |
2580 * @throws SQLException if a database access error occurs | |
2581 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
2582 * not support this method | |
2583 */ | |
2584 @Override | |
2585 public SQLXML getSQLXML(final String columnLabel) throws SQLException { | |
2586 throw newSQLFeatureNotSupportedException("getSQLXML"); | |
2587 } | |
2588 | |
2589 // This behaviour is according table B-6 of Sun JDBC Specification 3.0 | |
2590 private SimpleDateFormat dateFormat; | |
2591 private SimpleDateFormat timeFormat; | |
2592 private SimpleDateFormat timestampFormat; | |
2593 /** | |
2594 * Helper method which parses the date/time value for columns of type | |
2595 * TIME, DATE and TIMESTAMP. For the types CHAR, VARCHAR and | |
2596 * LONGVARCHAR an attempt is made to parse the date according to the | |
2597 * given type. The given Calender object is filled with the parsed | |
2598 * data. Optional fractional seconds (nanos) are returned by this | |
2599 * method. If the underlying type of the column is none of the | |
2600 * mentioned six, January 1st 1970 0:00:00 GMT is returned.<br /> | |
2601 * The dates are parsed with the given Calendar. | |
2602 * | |
2603 * @param cal the Calendar to use/fill when parsing the date/time | |
2604 * @param col the column to parse | |
2605 * @param type the corresponding java.sql.Types type of the calling function | |
2606 * @return the fractional seconds (nanos) or -1 if the value is NULL | |
2607 * @throws SQLException if a database error occurs | |
2608 */ | |
2609 private final int getJavaDate(final Calendar cal, final int columnIndex, int type) | |
2610 throws SQLException | |
2611 { | |
2612 checkNotClosed(); | |
2613 if (cal == null) | |
2614 throw new IllegalArgumentException("No Calendar object given!"); | |
2615 | |
2616 final String monetDateStr; | |
2617 final String monetDate; | |
2618 final String MonetDBType; | |
2619 int JdbcType; | |
2620 boolean negativeYear = false; | |
2621 try { | |
2622 monetDateStr = tlp.values[columnIndex - 1]; | |
2623 if (monetDateStr == null) { | |
2624 lastReadWasNull = true; | |
2625 return -1; | |
2626 } | |
2627 lastReadWasNull = false; | |
2628 MonetDBType = types[columnIndex - 1]; | |
2629 JdbcType = JdbcSQLTypes[columnIndex - 1]; | |
2630 // If we got a string type, set the JdbcType to the given type | |
2631 // so we attempt to parse it as the caller thinks it is. | |
2632 if (JdbcType == Types.CHAR || | |
2633 JdbcType == Types.VARCHAR || | |
2634 JdbcType == Types.LONGVARCHAR || | |
2635 JdbcType == Types.CLOB) | |
2636 { | |
2637 JdbcType = type; | |
2638 } | |
2639 | |
2640 if ((JdbcType == Types.DATE || JdbcType == Types.TIMESTAMP || JdbcType == Types.TIMESTAMP_WITH_TIMEZONE) | |
2641 && monetDateStr.startsWith("-")) { | |
2642 // the SimpleDateFormat parsers do not support to parse negative year numbers, deal with it separately | |
2643 negativeYear = true; | |
2644 monetDate = monetDateStr.substring(1); | |
2645 } else { | |
2646 monetDate = monetDateStr; | |
2647 } | |
2648 } catch (IndexOutOfBoundsException e) { | |
2649 throw newSQLInvalidColumnIndexException(columnIndex); | |
2650 } | |
2651 | |
2652 TimeZone ptz = cal.getTimeZone(); | |
2653 | |
2654 // it is important to parse the time in the given timezone in | |
2655 // order to get a correct (UTC) time value, hence we need to | |
2656 // parse it first | |
2657 if (MonetDBType != null && ("timetz".equals(MonetDBType) || "timestamptz".equals(MonetDBType))) { | |
2658 int vallen = monetDate.length(); | |
2659 if (vallen >= 6) { | |
2660 // MonetDB/SQL99: Sign TwoDigitHours : Minutes | |
2661 ptz = TimeZone.getTimeZone("GMT" + monetDate.substring(vallen - 6, vallen)); | |
2662 } | |
2663 } | |
2664 | |
2665 java.util.Date pdate = null; | |
2666 final java.text.ParsePosition ppos = new java.text.ParsePosition(0); | |
2667 switch(JdbcType) { | |
2668 case Types.DATE: | |
2669 if (dateFormat == null) { | |
2670 // first time usage, create and keep the dateFormat object for next usage | |
2671 dateFormat = new SimpleDateFormat("yyyy-MM-dd"); | |
2672 } | |
2673 dateFormat.setTimeZone(ptz); | |
2674 pdate = dateFormat.parse(monetDate, ppos); | |
2675 break; | |
2676 case Types.TIME: | |
2677 case Types.TIME_WITH_TIMEZONE: | |
2678 if (timeFormat == null) { | |
2679 // first time usage, create and keep the timeFormat object for next usage | |
2680 timeFormat = new SimpleDateFormat("HH:mm:ss"); | |
2681 } | |
2682 timeFormat.setTimeZone(ptz); | |
2683 pdate = timeFormat.parse(monetDate, ppos); | |
2684 break; | |
2685 case Types.TIMESTAMP: | |
2686 case Types.TIMESTAMP_WITH_TIMEZONE: | |
2687 if (timestampFormat == null) { | |
2688 // first time usage, create and keep the timestampFormat object for next usage | |
2689 timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
2690 } | |
2691 timestampFormat.setTimeZone(ptz); | |
2692 pdate = timestampFormat.parse(monetDate, ppos); | |
2693 // if parsing with timestampFormat failed try to parse it in dateFormat | |
2694 if (pdate == null && monetDate.length() <= 10 && monetDate.contains("-")) { | |
2695 if (dateFormat == null) { | |
2696 // first time usage, create and keep the dateFormat object for next usage | |
2697 dateFormat = new SimpleDateFormat("yyyy-MM-dd"); | |
2698 } | |
2699 dateFormat.setTimeZone(ptz); | |
2700 pdate = dateFormat.parse(monetDate, ppos); | |
2701 } | |
2702 break; | |
2703 default: | |
2704 throw new SQLException("Internal error, unsupported data type: " + type, "01M03"); | |
2705 } | |
2706 if (pdate == null) { | |
2707 // parsing failed | |
2708 final String errMsg; | |
2709 final int epos = ppos.getErrorIndex(); | |
2710 if (epos == -1) { | |
2711 errMsg = "parsing '" + monetDateStr + "' failed"; | |
2712 } else if (epos < monetDate.length()) { | |
2713 errMsg = "parsing failed," + | |
2714 " found: '" + monetDate.charAt(epos) + "'" + | |
2715 " in: \"" + monetDateStr + "\"" + | |
2716 " at pos: " + (epos + (negativeYear ? 2 : 1)); | |
2717 } else { | |
2718 errMsg = "parsing failed, expected more data after '" + monetDateStr + "'"; | |
2719 } | |
2720 throw new SQLException(errMsg, "01M10"); | |
2721 } | |
2722 | |
2723 cal.setTime(pdate); | |
2724 if (negativeYear) { | |
2725 // System.out.println("Current cal: " + cal.toString()); | |
2726 // using cal.set(Calendar.YEAR, -(cal.get(Calendar.YEAR))); does not work. We must set the ERA instead | |
2727 cal.set(Calendar.ERA, java.util.GregorianCalendar.BC); | |
2728 // System.out.println("Corrected cal: " + cal.toString()); | |
2729 } | |
2730 | |
2731 if (JdbcType == Types.TIME | |
2732 || JdbcType == Types.TIME_WITH_TIMEZONE | |
2733 || JdbcType == Types.TIMESTAMP | |
2734 || JdbcType == Types.TIMESTAMP_WITH_TIMEZONE) { | |
2735 // parse additional nanos (if any) | |
2736 int nanos = 0; | |
2737 int pos = ppos.getIndex(); | |
2738 final char[] monDate = monetDate.toCharArray(); | |
2739 if (pos < monDate.length && monDate[pos] == '.') { | |
2740 pos++; | |
2741 try { | |
2742 int ctr; | |
2743 nanos = getIntrinsicValue(monDate[pos], pos++); | |
2744 for (ctr = 1; | |
2745 pos < monDate.length && | |
2746 monDate[pos] >= '0' && | |
2747 monDate[pos] <= '9'; | |
2748 ctr++) | |
2749 { | |
2750 if (ctr < 9) { | |
2751 nanos *= 10; | |
2752 nanos += (getIntrinsicValue(monDate[pos], pos)); | |
2753 } | |
2754 if (ctr == 2) // we have three at this point | |
2755 cal.set(Calendar.MILLISECOND, nanos); | |
2756 pos++; | |
2757 } | |
2758 while (ctr++ < 9) | |
2759 nanos *= 10; | |
2760 } catch (MCLParseException e) { | |
2761 addWarning(e.getMessage() + | |
2762 " found: '" + monDate[e.getErrorOffset()] + "'" + | |
2763 " in: \"" + monetDate + "\"" + | |
2764 " at pos: " + e.getErrorOffset(), "01M10"); | |
2765 // default value | |
2766 nanos = 0; | |
2767 } | |
2768 } | |
2769 return nanos; | |
2770 } | |
2771 | |
2772 return 0; | |
2773 } | |
2774 | |
2775 /** | |
2776 * Small helper method that returns the intrinsic value of a char if | |
2777 * it represents a digit. If a non-digit character is encountered | |
2778 * an MCLParseException is thrown. | |
2779 * | |
2780 * @param c the char | |
2781 * @param pos the position | |
2782 * @return the intrinsic value of the char | |
2783 * @throws MCLParseException if c is not a digit | |
2784 */ | |
2785 private static final int getIntrinsicValue(final char c, final int pos) | |
2786 throws MCLParseException | |
2787 { | |
2788 // note: don't use Character.isDigit() here, because | |
2789 // we only want ISO-LATIN-1 digits | |
2790 if (c >= '0' && c <= '9') { | |
2791 return (int)c - (int)'0'; | |
2792 } else { | |
2793 throw new MCLParseException("Expected a digit", pos); | |
2794 } | |
2795 } | |
2796 | |
2797 /** | |
2798 * Retrieves the value of the designated column in the current row of this | |
2799 * ResultSet object as a java.sql.Date object in the Java programming | |
2800 * language. | |
2801 * | |
2802 * @param columnIndex the first column is 1, the second is 2, ... | |
2803 * @return the column value as a java.sql.Date object; if the value is SQL NULL, the value returned is null | |
2804 * @throws SQLException if a database access error occurs | |
2805 * @see #getDate(int col, Calendar cal) | |
2806 */ | |
2807 @Override | |
2808 public java.sql.Date getDate(final int columnIndex) throws SQLException { | |
2809 return getDate(columnIndex, null); | |
2810 } | |
2811 | |
2812 /** | |
2813 * Retrieves the value of the designated column in the current row of this | |
2814 * ResultSet object as a java.sql.Date object in the Java programming | |
2815 * language. This method uses the given calendar to construct an appropriate | |
2816 * millisecond value for the date if the underlying database does not store | |
2817 * timezone information. | |
2818 * | |
2819 * @param columnIndex the first column is 1, the second is 2, ... | |
2820 * @param cal the java.util.Calendar object to use in constructing the date | |
2821 * @return the column value as a java.sql.Date object; if the value is SQL NULL, the value returned is null | |
2822 * @throws SQLException if a database access error occurs | |
2823 */ | |
2824 @Override | |
2825 public java.sql.Date getDate(final int columnIndex, Calendar cal) | |
2826 throws SQLException | |
2827 { | |
2828 checkNotClosed(); | |
2829 try { | |
2830 final String val = tlp.values[columnIndex - 1]; | |
2831 if (val == null) { | |
2832 lastReadWasNull = true; | |
2833 return null; | |
2834 } | |
2835 lastReadWasNull = false; | |
2836 if (cal == null) { | |
2837 // try to convert string directly to a Date object | |
2838 // Note: the string must be in JDBC date escape format: yyyy-[m]m-[d]d | |
2839 try { | |
2840 return java.sql.Date.valueOf(val); | |
2841 } catch (IllegalArgumentException iae) { | |
2842 // this happens if string doesn't match the format, such as for years < 1000 (including negative years) | |
2843 // in those cases just continue and use slower getJavaDate(cal, columnIndex, Types.DATE) method | |
2844 } | |
2845 cal = Calendar.getInstance(); | |
2846 } | |
2847 final int ret = getJavaDate(cal, columnIndex, Types.DATE); | |
2848 return ret == -1 ? null : new java.sql.Date(cal.getTimeInMillis()); | |
2849 } catch (IndexOutOfBoundsException e) { | |
2850 throw newSQLInvalidColumnIndexException(columnIndex); | |
2851 } | |
2852 } | |
2853 | |
2854 /** | |
2855 * Retrieves the value of the designated column in the current row of this | |
2856 * ResultSet object as a java.sql.Date object in the Java programming | |
2857 * language. | |
2858 * | |
2859 * @param columnLabel the SQL name of the column from which to retrieve the value | |
2860 * @return the column value as a java.sql.Date object; if the value is SQL NULL, the value returned is null | |
2861 * @throws SQLException if a database access error occurs | |
2862 */ | |
2863 @Override | |
2864 public java.sql.Date getDate(final String columnLabel) throws SQLException { | |
2865 return getDate(findColumn(columnLabel), null); | |
2866 } | |
2867 | |
2868 /** | |
2869 * Retrieves the value of the designated column in the current row of this | |
2870 * ResultSet object as a java.sql.Date object in the Java programming | |
2871 * language. This method uses the given calendar to construct an appropriate | |
2872 * millisecond value for the date if the underlying database does not store | |
2873 * timezone information. | |
2874 * | |
2875 * @param columnLabel the SQL name of the column from which to retrieve the value | |
2876 * @param cal the java.util.Calendar object to use in constructing the date | |
2877 * @return the column value as a java.sql.Date object; if the value is SQL NULL, the value returned is null | |
2878 * @throws SQLException if a database access error occurs | |
2879 */ | |
2880 @Override | |
2881 public java.sql.Date getDate(final String columnLabel, final Calendar cal) | |
2882 throws SQLException | |
2883 { | |
2884 return getDate(findColumn(columnLabel), cal); | |
2885 } | |
2886 | |
2887 /** | |
2888 * Retrieves the value of the designated column in the current row of this | |
2889 * ResultSet object as a java.sql.Time object in the Java programming | |
2890 * language. | |
2891 * | |
2892 * @param columnIndex the first column is 1, the second is 2, ... | |
2893 * @return the column value as a java.sql.Time object; if the value is SQL NULL, the value returned is null | |
2894 * @throws SQLException if a database access error occurs | |
2895 */ | |
2896 @Override | |
2897 public Time getTime(final int columnIndex) throws SQLException { | |
2898 return getTime(columnIndex, null); | |
2899 } | |
2900 | |
2901 /** | |
2902 * Retrieves the value of the designated column in the current row of | |
2903 * this ResultSet object as a java.sql.Time object in the Java programming | |
2904 * language. This method uses the given calendar to construct an appropriate | |
2905 * millisecond value for the time if the underlying database does not store | |
2906 * timezone information. | |
2907 * | |
2908 * @param columnIndex the first column is 1, the second is 2, ... | |
2909 * @param cal the java.util.Calendar object to use in constructing the timestamp | |
2910 * @return the column value as a java.sql.Time object; if the value is SQL NULL, the value returned is null | |
2911 * @throws SQLException if a database access error occurs | |
2912 */ | |
2913 @Override | |
2914 public Time getTime(final int columnIndex, Calendar cal) | |
2915 throws SQLException | |
2916 { | |
2917 checkNotClosed(); | |
2918 try { | |
2919 final String val = tlp.values[columnIndex - 1]; | |
2920 if (val == null) { | |
2921 lastReadWasNull = true; | |
2922 return null; | |
2923 } | |
2924 lastReadWasNull = false; | |
2925 if (cal == null) { | |
2926 // try to convert string directly to a Time object | |
2927 // Note: the string must be in JDBC time escape format: hh:mm:ss | |
2928 try { | |
2929 return Time.valueOf(val); | |
2930 } catch (IllegalArgumentException iae) { | |
2931 // this happens if string doesn't match the format or hh >= 24 or mm >= 60 or ss >= 60 | |
2932 // in those cases just continue and use slower getJavaDate(cal, columnIndex, Types.TIME) method | |
2933 } | |
2934 cal = Calendar.getInstance(); | |
2935 } | |
2936 final int ret = getJavaDate(cal, columnIndex, Types.TIME); | |
2937 return ret == -1 ? null : new Time(cal.getTimeInMillis()); | |
2938 } catch (IndexOutOfBoundsException e) { | |
2939 throw newSQLInvalidColumnIndexException(columnIndex); | |
2940 } | |
2941 } | |
2942 | |
2943 /** | |
2944 * Retrieves the value of the designated column in the current row of this | |
2945 * ResultSet object as a java.sql.Time object in the Java programming | |
2946 * language. | |
2947 * | |
2948 * @param columnLabel the SQL name of the column | |
2949 * @return the column value as a java.sql.Time object; if the value is SQL NULL, the value returned is null | |
2950 * @throws SQLException if a database access error occurs | |
2951 */ | |
2952 @Override | |
2953 public Time getTime(final String columnLabel) throws SQLException { | |
2954 return getTime(findColumn(columnLabel), null); | |
2955 } | |
2956 | |
2957 /** | |
2958 * Retrieves the value of the designated column in the current row of | |
2959 * this ResultSet object as a java.sql.Time object in the Java programming | |
2960 * language. This method uses the given calendar to construct an appropriate | |
2961 * millisecond value for the time if the underlying database does not store | |
2962 * timezone information. | |
2963 * | |
2964 * @param columnLabel the SQL name of the column | |
2965 * @param cal the java.util.Calendar object to use in constructing the timestamp | |
2966 * @return the column value as a java.sql.Time object; if the value is SQL NULL, the value returned is null | |
2967 * @throws SQLException if a database access error occurs | |
2968 */ | |
2969 @Override | |
2970 public Time getTime(final String columnLabel, final Calendar cal) | |
2971 throws SQLException | |
2972 { | |
2973 return getTime(findColumn(columnLabel), cal); | |
2974 } | |
2975 | |
2976 /** | |
2977 * Retrieves the value of the designated column in the current row of this | |
2978 * ResultSet object as a java.sql.Timestamp object in the Java programming | |
2979 * language. | |
2980 * | |
2981 * @param columnIndex the first column is 1, the second is 2, ... | |
2982 * @return the column value as a java.sql.Timestamp object; if the value is SQL NULL, the value returned is null | |
2983 * @throws SQLException if a database access error occurs | |
2984 */ | |
2985 @Override | |
2986 public Timestamp getTimestamp(final int columnIndex) throws SQLException { | |
2987 return getTimestamp(columnIndex, null); | |
2988 } | |
2989 | |
2990 /** | |
2991 * Retrieves the value of the designated column in the current row of this | |
2992 * ResultSet object as a java.sql.Timestamp object in the Java programming | |
2993 * language. This method uses the given calendar to construct an appropriate | |
2994 * millisecond value for the timestamp if the underlying database does not | |
2995 * store timezone information. | |
2996 * | |
2997 * @param columnIndex the first column is 1, the second is 2, ... | |
2998 * @param cal the java.util.Calendar object to use in constructing the timestamp | |
2999 * @return the column value as a java.sql.Timestamp object; if the value is SQL NULL, the value returned is null | |
3000 * @throws SQLException if a database access error occurs | |
3001 */ | |
3002 @Override | |
3003 public Timestamp getTimestamp(final int columnIndex, Calendar cal) | |
3004 throws SQLException | |
3005 { | |
3006 checkNotClosed(); | |
3007 try { | |
3008 final String val = tlp.values[columnIndex - 1]; | |
3009 if (val == null) { | |
3010 lastReadWasNull = true; | |
3011 return null; | |
3012 } | |
3013 lastReadWasNull = false; | |
3014 if (cal == null) { | |
3015 // try to convert the string directly to a Timestamp object | |
3016 // Note: the string must be in JDBC timestamp escape format: yyyy-[m]m-[d]d hh:mm:ss[.f...] | |
3017 try { | |
3018 return Timestamp.valueOf(val); | |
3019 } catch (IllegalArgumentException iae) { | |
3020 // this happens if string doesn't match the format, such as for years < 1000 (including negative years) | |
3021 // in those cases just continue and use slower getJavaDate(cal, columnIndex, Types.TIMESTAMP) method | |
3022 } | |
3023 cal = Calendar.getInstance(); | |
3024 } | |
3025 final int nanos = getJavaDate(cal, columnIndex, Types.TIMESTAMP); | |
3026 if (nanos == -1) | |
3027 return null; | |
3028 | |
3029 final Timestamp ts = new Timestamp(cal.getTimeInMillis()); | |
3030 ts.setNanos(nanos); | |
3031 return ts; | |
3032 } catch (IndexOutOfBoundsException e) { | |
3033 throw newSQLInvalidColumnIndexException(columnIndex); | |
3034 } | |
3035 } | |
3036 | |
3037 /** | |
3038 * Retrieves the value of the designated column in the current row of this | |
3039 * ResultSet object as a java.sql.Timestamp object in the Java programming | |
3040 * language. | |
3041 * | |
3042 * @param columnLabel the SQL name of the column | |
3043 * @return the column value as a java.sql.Timestamp object; if the value is SQL NULL, the value returned is null | |
3044 * @throws SQLException if a database access error occurs | |
3045 */ | |
3046 @Override | |
3047 public Timestamp getTimestamp(final String columnLabel) throws SQLException { | |
3048 return getTimestamp(findColumn(columnLabel), null); | |
3049 } | |
3050 | |
3051 /** | |
3052 * Retrieves the value of the designated column in the current row of this | |
3053 * ResultSet object as a java.sql.Timestamp object in the Java programming | |
3054 * language. This method uses the given calendar to construct an appropriate | |
3055 * millisecond value for the timestamp if the underlying database does not | |
3056 * store timezone information. | |
3057 * | |
3058 * @param columnLabel the SQL name of the column | |
3059 * @param cal the java.util.Calendar object to use in constructing the timestamp | |
3060 * @return the column value as a java.sql.Timestamp object; if the value is SQL NULL, the value returned is null | |
3061 * @throws SQLException if a database access error occurs | |
3062 */ | |
3063 @Override | |
3064 public Timestamp getTimestamp(final String columnLabel, final Calendar cal) | |
3065 throws SQLException | |
3066 { | |
3067 return getTimestamp(findColumn(columnLabel), cal); | |
3068 } | |
3069 | |
3070 /** | |
3071 * Retrieves the type of this ResultSet object. The type is determined by | |
3072 * the Statement object that created the result set. | |
3073 * | |
3074 * @return ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, | |
3075 * or ResultSet.TYPE_SCROLL_SENSITIVE | |
3076 */ | |
3077 @Override | |
3078 public int getType() { | |
3079 return type; | |
3080 } | |
3081 | |
3082 /** | |
3083 * Retrieves the value of the designated column in the current row | |
3084 * of this ResultSet object as a java.net.URL object in the Java | |
3085 * programming language. | |
3086 * | |
3087 * @param columnIndex the index of the column 1 is the first, 2 is the second,... | |
3088 * @return the column value as a java.net.URL object; if the value is SQL NULL, the value returned is null | |
3089 * @throws SQLException if a database access error occurs, or if a URL is malformed | |
3090 */ | |
3091 @Override | |
3092 public URL getURL(final int columnIndex) throws SQLException { | |
3093 checkNotClosed(); | |
3094 try { | |
3095 final String val = tlp.values[columnIndex - 1]; | |
3096 if (val == null) { | |
3097 lastReadWasNull = true; | |
3098 return null; | |
3099 } | |
3100 lastReadWasNull = false; | |
3101 try { | |
3102 return new URL(val); | |
3103 } catch (java.net.MalformedURLException e) { | |
3104 throw new SQLException(e.getMessage(), "M1M05"); | |
3105 } | |
3106 } catch (IndexOutOfBoundsException e) { | |
3107 throw newSQLInvalidColumnIndexException(columnIndex); | |
3108 } | |
3109 } | |
3110 | |
3111 /** | |
3112 * Retrieves the value of the designated column in the current row | |
3113 * of this ResultSet object as a java.net.URL object in the Java | |
3114 * programming language. | |
3115 * | |
3116 * @param columnLabel the SQL name of the column | |
3117 * @return the column value as a java.net.URL object; if the value is SQL NULL, the value returned is null | |
3118 * @throws SQLException if a database access error occurs, or if a URL is malformed | |
3119 */ | |
3120 @Override | |
3121 public URL getURL(final String columnLabel) throws SQLException { | |
3122 return getURL(findColumn(columnLabel)); | |
3123 } | |
3124 | |
3125 /** | |
3126 * Retrieves the first warning reported by calls on this ResultSet object. | |
3127 * If there is more than one warning, subsequent warnings will be chained to | |
3128 * the first one and can be retrieved by calling the method | |
3129 * SQLWarning.getNextWarning on the warning that was retrieved previously. | |
3130 * | |
3131 * This method may not be called on a closed result set; doing so will cause | |
3132 * an SQLException to be thrown. | |
3133 * | |
3134 * Note: Subsequent warnings will be chained to this SQLWarning. | |
3135 * | |
3136 * @return the first SQLWarning object or null if there are none | |
3137 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3138 */ | |
3139 @Override | |
3140 public SQLWarning getWarnings() throws SQLException { | |
3141 checkNotClosed(); | |
3142 // if there are no warnings, this will be null, which fits with the | |
3143 // specification. | |
3144 return warnings; | |
3145 } | |
3146 | |
3147 /** | |
3148 * Retrieves whether the cursor is after the last row in this ResultSet | |
3149 * object. | |
3150 * | |
3151 * @return true if the cursor is after the last row; false if the cursor is | |
3152 * at any other position or the result set contains no rows | |
3153 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3154 */ | |
3155 @Override | |
3156 public boolean isAfterLast() throws SQLException { | |
3157 checkNotClosed(); | |
3158 return curRow == tupleCount + 1; | |
3159 } | |
3160 | |
3161 /** | |
3162 * Retrieves whether the cursor is before the first row in this ResultSet | |
3163 * object. | |
3164 * | |
3165 * @return true if the cursor is before the first row; false if the cursor | |
3166 * is at any other position or the result set contains no rows | |
3167 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3168 */ | |
3169 @Override | |
3170 public boolean isBeforeFirst() throws SQLException { | |
3171 checkNotClosed(); | |
3172 return curRow == 0; | |
3173 } | |
3174 | |
3175 /** | |
3176 * Retrieves whether this ResultSet object has been closed. A | |
3177 * ResultSet is closed if the method close has been called on it, or | |
3178 * if it is automatically closed. | |
3179 * | |
3180 * @return true if this ResultSet object is closed; false if it is still open | |
3181 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3182 */ | |
3183 @Override | |
3184 public boolean isClosed() throws SQLException { | |
3185 return header != null && header.isClosed(); | |
3186 } | |
3187 | |
3188 /** | |
3189 * Retrieves whether the cursor is on the first row of this ResultSet | |
3190 * object. | |
3191 * | |
3192 * @return true if the cursor is on the first row; false otherwise | |
3193 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3194 */ | |
3195 @Override | |
3196 public boolean isFirst() throws SQLException { | |
3197 checkNotClosed(); | |
3198 return curRow == 1; | |
3199 } | |
3200 | |
3201 /** | |
3202 * Retrieves whether the cursor is on the last row of this ResultSet object. | |
3203 * | |
3204 * @return true if the cursor is on the last row; false otherwise | |
3205 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3206 */ | |
3207 @Override | |
3208 public boolean isLast() throws SQLException { | |
3209 checkNotClosed(); | |
3210 return curRow == tupleCount; | |
3211 } | |
3212 | |
3213 /** | |
3214 * Moves the cursor to the last row in this ResultSet object. | |
3215 * | |
3216 * @return true if the cursor is on a valid row; false if there are no rows | |
3217 * in the result set | |
3218 * @throws SQLException if a database access error occurs or the result set | |
3219 * type is TYPE_FORWARD_ONLY | |
3220 * @throws SQLException if a database access error occurs or this method is called on a closed result set | |
3221 */ | |
3222 @Override | |
3223 public boolean last() throws SQLException { | |
3224 return absolute(-1); | |
3225 } | |
3226 | |
3227 /** | |
3228 * Moves the cursor down one row from its current position. A ResultSet | |
3229 * cursor is initially positioned before the first row; the first call to | |
3230 * the method next makes the first row the current row; the second call | |
3231 * makes the second row the current row, and so on. | |
3232 * | |
3233 * If an input stream is open for the current row, a call to the method | |
3234 * next will implicitly close it. A ResultSet object's warning chain is | |
3235 * cleared when a new row is read. | |
3236 * | |
3237 * @return true if the new current row is valid; false if there are no | |
3238 * more rows | |
3239 * @throws SQLException if a database access error occurs or ResultSet is | |
3240 * closed | |
3241 */ | |
3242 @Override | |
3243 public boolean next() throws SQLException { | |
3244 return relative(1); | |
3245 } | |
3246 | |
3247 /** | |
3248 * Moves the cursor to the previous row in this ResultSet object. | |
3249 * | |
3250 * @return true if the cursor is on a valid row; false if it is off | |
3251 * the result set | |
3252 * @throws SQLException if a database access error occurs or ResultSet is | |
3253 * closed or the result set type is TYPE_FORWARD_ONLY | |
3254 */ | |
3255 @Override | |
3256 public boolean previous() throws SQLException { | |
3257 return relative(-1); | |
3258 } | |
3259 | |
3260 /** | |
3261 * Moves the cursor a relative number of rows, either positive or negative. | |
3262 * Attempting to move beyond the first/last row in the result set positions | |
3263 * the cursor before/after the the first/last row. Calling relative(0) is | |
3264 * valid, but does not change the cursor position. | |
3265 * | |
3266 * Note: Calling the method relative(1) is identical to calling the method | |
3267 * next() and calling the method relative(-1) is identical to calling the | |
3268 * method previous(). | |
3269 * | |
3270 * @param rows an int specifying the number of rows to move from the current | |
3271 * row; a positive number moves the cursor forward; a negative number | |
3272 * moves the cursor backward | |
3273 * @return true if the cursor is on a row; false otherwise | |
3274 * @throws SQLException if a database access error occurs, there is no current | |
3275 * row, or the result set type is TYPE_FORWARD_ONLY | |
3276 */ | |
3277 @Override | |
3278 public boolean relative(final int rows) throws SQLException { | |
3279 return absolute(curRow + rows); | |
3280 } | |
3281 | |
3282 /** | |
3283 * Retrieves whether a row has been deleted. A deleted row may leave a visible "hole" in a result set. | |
3284 * This method can be used to detect holes in a result set. | |
3285 * The value returned depends on whether or not this ResultSet object can detect deletions. | |
3286 * | |
3287 * Note: Support for the rowDeleted method is optional with a result set concurrency of CONCUR_READ_ONLY | |
3288 * | |
3289 * Returns: true if the current row is detected to have been deleted by the owner or another; false otherwise | |
3290 * | |
3291 * Throws: | |
3292 * SQLException - if a database access error occurs or this method is called on a closed result set | |
3293 * Since: 1.2 | |
3294 * See Also: DatabaseMetaData.deletesAreDetected(int) | |
3295 */ | |
3296 @Override | |
3297 public boolean rowDeleted() throws SQLException { | |
3298 checkNotClosed(); | |
3299 return false; | |
3300 } | |
3301 | |
3302 /** | |
3303 * Retrieves whether the current row has had an insertion. | |
3304 * The value returned depends on whether or not this ResultSet object can detect visible inserts. | |
3305 * | |
3306 * Note: Support for the rowInserted method is optional with a result set concurrency of CONCUR_READ_ONLY | |
3307 * | |
3308 * Returns: true if the current row is detected to have been inserted; false otherwise | |
3309 * | |
3310 * Throws: | |
3311 * SQLException - if a database access error occurs or this method is called on a closed result set | |
3312 * Since: 1.2 | |
3313 * See Also: DatabaseMetaData.insertsAreDetected(int) | |
3314 */ | |
3315 @Override | |
3316 public boolean rowInserted() throws SQLException { | |
3317 checkNotClosed(); | |
3318 return false; | |
3319 } | |
3320 | |
3321 /** | |
3322 * Retrieves whether the current row has been updated. | |
3323 * The value returned depends on whether or not the result set can detect updates. | |
3324 * | |
3325 * Note: Support for the rowUpdated method is optional with a result set concurrency of CONCUR_READ_ONLY | |
3326 * | |
3327 * Returns: true if the current row is detected to have been visibly updated by the owner or another; false otherwise | |
3328 * | |
3329 * Throws: | |
3330 * SQLException - if a database access error occurs or this method is called on a closed result set | |
3331 * Since: 1.2 | |
3332 * See Also: DatabaseMetaData.updatesAreDetected(int) | |
3333 */ | |
3334 @Override | |
3335 public boolean rowUpdated() throws SQLException { | |
3336 checkNotClosed(); | |
3337 return false; | |
3338 } | |
3339 | |
3340 | |
3341 /* Next methods are all related to updateable result sets, which we do not support. | |
3342 * @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method | |
3343 */ | |
3344 @Override | |
3345 public void cancelRowUpdates() throws SQLException { | |
3346 throw newSQLFeatureNotSupportedException("cancelRowUpdates"); | |
3347 } | |
3348 | |
3349 @Override | |
3350 public void deleteRow() throws SQLException { | |
3351 throw newSQLFeatureNotSupportedException("deleteRow"); | |
3352 } | |
3353 | |
3354 @Override | |
3355 public void insertRow() throws SQLException { | |
3356 throw newSQLFeatureNotSupportedException("insertRow"); | |
3357 } | |
3358 | |
3359 @Override | |
3360 public void moveToCurrentRow() throws SQLException { | |
3361 throw newSQLFeatureNotSupportedException("moveToCurrentRow"); | |
3362 } | |
3363 | |
3364 @Override | |
3365 public void moveToInsertRow() throws SQLException { | |
3366 throw newSQLFeatureNotSupportedException("moveToInsertRow"); | |
3367 } | |
3368 | |
3369 @Override | |
3370 public void refreshRow() throws SQLException { | |
3371 throw newSQLFeatureNotSupportedException("refreshRow"); | |
3372 } | |
3373 | |
3374 | |
3375 @Override | |
3376 public void updateArray(int columnIndex, Array x) throws SQLException { | |
3377 throw newSQLFeatureNotSupportedException("updateArray"); | |
3378 } | |
3379 | |
3380 @Override | |
3381 public void updateArray(String columnLabel, Array x) throws SQLException { | |
3382 throw newSQLFeatureNotSupportedException("updateArray"); | |
3383 } | |
3384 | |
3385 @Override | |
3386 public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { | |
3387 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3388 } | |
3389 | |
3390 @Override | |
3391 public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { | |
3392 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3393 } | |
3394 | |
3395 @Override | |
3396 public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { | |
3397 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3398 } | |
3399 | |
3400 @Override | |
3401 public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { | |
3402 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3403 } | |
3404 | |
3405 @Override | |
3406 public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { | |
3407 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3408 } | |
3409 | |
3410 @Override | |
3411 public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { | |
3412 throw newSQLFeatureNotSupportedException("updateAsciiStream"); | |
3413 } | |
3414 | |
3415 @Override | |
3416 public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { | |
3417 throw newSQLFeatureNotSupportedException("updateBigDecimal"); | |
3418 } | |
3419 | |
3420 @Override | |
3421 public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { | |
3422 throw newSQLFeatureNotSupportedException("updateBigDecimal"); | |
3423 } | |
3424 | |
3425 @Override | |
3426 public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { | |
3427 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3428 } | |
3429 | |
3430 @Override | |
3431 public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { | |
3432 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3433 } | |
3434 | |
3435 @Override | |
3436 public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { | |
3437 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3438 } | |
3439 | |
3440 @Override | |
3441 public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { | |
3442 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3443 } | |
3444 | |
3445 @Override | |
3446 public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { | |
3447 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3448 } | |
3449 | |
3450 @Override | |
3451 public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { | |
3452 throw newSQLFeatureNotSupportedException("updateBinaryStream"); | |
3453 } | |
3454 | |
3455 @Override | |
3456 public void updateBlob(int columnIndex, Blob x) throws SQLException { | |
3457 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3458 } | |
3459 | |
3460 @Override | |
3461 public void updateBlob(int columnIndex, InputStream s) throws SQLException { | |
3462 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3463 } | |
3464 | |
3465 @Override | |
3466 public void updateBlob(int columnIndex, InputStream s, long length) throws SQLException { | |
3467 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3468 } | |
3469 | |
3470 @Override | |
3471 public void updateBlob(String columnLabel, Blob x) throws SQLException { | |
3472 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3473 } | |
3474 | |
3475 @Override | |
3476 public void updateBlob(String columnLabel, InputStream s) throws SQLException { | |
3477 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3478 } | |
3479 | |
3480 @Override | |
3481 public void updateBlob(String columnLabel, InputStream s, long length) throws SQLException { | |
3482 throw newSQLFeatureNotSupportedException("updateBlob"); | |
3483 } | |
3484 | |
3485 @Override | |
3486 public void updateBoolean(int columnIndex, boolean x) throws SQLException { | |
3487 throw newSQLFeatureNotSupportedException("updateBoolean"); | |
3488 } | |
3489 | |
3490 @Override | |
3491 public void updateBoolean(String columnLabel, boolean x) throws SQLException { | |
3492 throw newSQLFeatureNotSupportedException("updateBoolean"); | |
3493 } | |
3494 | |
3495 @Override | |
3496 public void updateByte(int columnIndex, byte x) throws SQLException { | |
3497 throw newSQLFeatureNotSupportedException("updateByte"); | |
3498 } | |
3499 | |
3500 @Override | |
3501 public void updateByte(String columnLabel, byte x) throws SQLException { | |
3502 throw newSQLFeatureNotSupportedException("updateByte"); | |
3503 } | |
3504 | |
3505 @Override | |
3506 public void updateBytes(int columnIndex, byte[] x) throws SQLException { | |
3507 throw newSQLFeatureNotSupportedException("updateBytes"); | |
3508 } | |
3509 | |
3510 @Override | |
3511 public void updateBytes(String columnLabel, byte[] x) throws SQLException { | |
3512 throw newSQLFeatureNotSupportedException("updateBytes"); | |
3513 } | |
3514 | |
3515 @Override | |
3516 public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { | |
3517 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3518 } | |
3519 | |
3520 @Override | |
3521 public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { | |
3522 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3523 } | |
3524 | |
3525 @Override | |
3526 public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { | |
3527 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3528 } | |
3529 | |
3530 @Override | |
3531 public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { | |
3532 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3533 } | |
3534 | |
3535 @Override | |
3536 public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { | |
3537 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3538 } | |
3539 | |
3540 @Override | |
3541 public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { | |
3542 throw newSQLFeatureNotSupportedException("updateCharacterStream"); | |
3543 } | |
3544 | |
3545 @Override | |
3546 public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { | |
3547 throw newSQLFeatureNotSupportedException("updateNCharacterStream"); | |
3548 } | |
3549 | |
3550 @Override | |
3551 public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { | |
3552 throw newSQLFeatureNotSupportedException("updateNCharacterStream"); | |
3553 } | |
3554 | |
3555 @Override | |
3556 public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { | |
3557 throw newSQLFeatureNotSupportedException("updateNCharacterStream"); | |
3558 } | |
3559 | |
3560 @Override | |
3561 public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { | |
3562 throw newSQLFeatureNotSupportedException("updateNCharacterStream"); | |
3563 } | |
3564 | |
3565 @Override | |
3566 public void updateClob(int columnIndex, Clob x) throws SQLException { | |
3567 throw newSQLFeatureNotSupportedException("updateClob"); | |
3568 } | |
3569 | |
3570 @Override | |
3571 public void updateClob(int columnIndex, Reader r) throws SQLException { | |
3572 throw newSQLFeatureNotSupportedException("updateClob"); | |
3573 } | |
3574 | |
3575 @Override | |
3576 public void updateClob(int columnIndex, Reader r, long length) throws SQLException { | |
3577 throw newSQLFeatureNotSupportedException("updateClob"); | |
3578 } | |
3579 | |
3580 @Override | |
3581 public void updateClob(String columnLabel, Clob x) throws SQLException { | |
3582 throw newSQLFeatureNotSupportedException("updateClob"); | |
3583 } | |
3584 | |
3585 @Override | |
3586 public void updateClob(String columnLabel, Reader r) throws SQLException { | |
3587 throw newSQLFeatureNotSupportedException("updateClob"); | |
3588 } | |
3589 | |
3590 @Override | |
3591 public void updateClob(String columnLabel, Reader r, long length) throws SQLException { | |
3592 throw newSQLFeatureNotSupportedException("updateClob"); | |
3593 } | |
3594 | |
3595 @Override | |
3596 public void updateNClob(int columnIndex, NClob x) throws SQLException { | |
3597 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3598 } | |
3599 | |
3600 @Override | |
3601 public void updateNClob(int columnIndex, Reader r) throws SQLException { | |
3602 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3603 } | |
3604 | |
3605 @Override | |
3606 public void updateNClob(int columnIndex, Reader r, long length) throws SQLException { | |
3607 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3608 } | |
3609 | |
3610 @Override | |
3611 public void updateNClob(String columnLabel, NClob x) throws SQLException { | |
3612 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3613 } | |
3614 | |
3615 @Override | |
3616 public void updateNClob(String columnLabel, Reader r) throws SQLException { | |
3617 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3618 } | |
3619 | |
3620 @Override | |
3621 public void updateNClob(String columnLabel, Reader r, long length) throws SQLException { | |
3622 throw newSQLFeatureNotSupportedException("updateNClob"); | |
3623 } | |
3624 | |
3625 @Override | |
3626 public void updateDate(int columnIndex, java.sql.Date x) throws SQLException { | |
3627 throw newSQLFeatureNotSupportedException("updateDate"); | |
3628 } | |
3629 | |
3630 @Override | |
3631 public void updateDate(String columnLabel, java.sql.Date x) throws SQLException { | |
3632 throw newSQLFeatureNotSupportedException("updateDate"); | |
3633 } | |
3634 | |
3635 @Override | |
3636 public void updateDouble(int columnIndex, double x) throws SQLException { | |
3637 throw newSQLFeatureNotSupportedException("updateDouble"); | |
3638 } | |
3639 | |
3640 @Override | |
3641 public void updateDouble(String columnLabel, double x) throws SQLException { | |
3642 throw newSQLFeatureNotSupportedException("updateDouble"); | |
3643 } | |
3644 | |
3645 @Override | |
3646 public void updateFloat(int columnIndex, float x) throws SQLException { | |
3647 throw newSQLFeatureNotSupportedException("updateFloat"); | |
3648 } | |
3649 | |
3650 @Override | |
3651 public void updateFloat(String columnLabel, float x) throws SQLException { | |
3652 throw newSQLFeatureNotSupportedException("updateFloat"); | |
3653 } | |
3654 | |
3655 @Override | |
3656 public void updateInt(int columnIndex, int x) throws SQLException { | |
3657 throw newSQLFeatureNotSupportedException("updateInt"); | |
3658 } | |
3659 | |
3660 @Override | |
3661 public void updateInt(String columnLabel, int x) throws SQLException { | |
3662 throw newSQLFeatureNotSupportedException("updateInt"); | |
3663 } | |
3664 | |
3665 @Override | |
3666 public void updateLong(int columnIndex, long x) throws SQLException { | |
3667 throw newSQLFeatureNotSupportedException("updateLong"); | |
3668 } | |
3669 | |
3670 @Override | |
3671 public void updateLong(String columnLabel, long x) throws SQLException { | |
3672 throw newSQLFeatureNotSupportedException("updateLong"); | |
3673 } | |
3674 | |
3675 @Override | |
3676 public void updateNull(int columnIndex) throws SQLException { | |
3677 throw newSQLFeatureNotSupportedException("updateNull"); | |
3678 } | |
3679 | |
3680 @Override | |
3681 public void updateNull(String columnLabel) throws SQLException { | |
3682 throw newSQLFeatureNotSupportedException("updateNull"); | |
3683 } | |
3684 | |
3685 @Override | |
3686 public void updateObject(int columnIndex, Object x) throws SQLException { | |
3687 throw newSQLFeatureNotSupportedException("updateObject"); | |
3688 } | |
3689 | |
3690 @Override | |
3691 public void updateObject(int columnIndex, Object x, int scale) throws SQLException { | |
3692 throw newSQLFeatureNotSupportedException("updateObject"); | |
3693 } | |
3694 | |
3695 @Override | |
3696 public void updateObject(String columnLabel, Object x) throws SQLException { | |
3697 throw newSQLFeatureNotSupportedException("updateObject"); | |
3698 } | |
3699 | |
3700 @Override | |
3701 public void updateObject(String columnLabel, Object x, int scale) throws SQLException { | |
3702 throw newSQLFeatureNotSupportedException("updateObject"); | |
3703 } | |
3704 | |
3705 @Override | |
3706 public void updateRef(int columnIndex, Ref x) throws SQLException { | |
3707 throw newSQLFeatureNotSupportedException("updateRef"); | |
3708 } | |
3709 | |
3710 @Override | |
3711 public void updateRef(String columnLabel, Ref x) throws SQLException { | |
3712 throw newSQLFeatureNotSupportedException("updateRef"); | |
3713 } | |
3714 | |
3715 @Override | |
3716 public void updateRow() throws SQLException { | |
3717 throw newSQLFeatureNotSupportedException("updateRow"); | |
3718 } | |
3719 | |
3720 @Override | |
3721 public void updateRowId(int columnIndex, RowId x) throws SQLException { | |
3722 throw newSQLFeatureNotSupportedException("updateRowId"); | |
3723 } | |
3724 | |
3725 @Override | |
3726 public void updateRowId(String columnLabel, RowId x) throws SQLException { | |
3727 throw newSQLFeatureNotSupportedException("updateRowId"); | |
3728 } | |
3729 | |
3730 @Override | |
3731 public void updateShort(int columnIndex, short x) throws SQLException { | |
3732 throw newSQLFeatureNotSupportedException("updateShort"); | |
3733 } | |
3734 | |
3735 @Override | |
3736 public void updateShort(String columnLabel, short x) throws SQLException { | |
3737 throw newSQLFeatureNotSupportedException("updateShort"); | |
3738 } | |
3739 | |
3740 @Override | |
3741 public void updateString(int columnIndex, String x) throws SQLException { | |
3742 throw newSQLFeatureNotSupportedException("updateString"); | |
3743 } | |
3744 | |
3745 @Override | |
3746 public void updateString(String columnLabel, String x) throws SQLException { | |
3747 throw newSQLFeatureNotSupportedException("updateString"); | |
3748 } | |
3749 | |
3750 @Override | |
3751 public void updateNString(int columnIndex, String x) throws SQLException { | |
3752 throw newSQLFeatureNotSupportedException("updateNString"); | |
3753 } | |
3754 | |
3755 @Override | |
3756 public void updateNString(String columnLabel, String x) throws SQLException { | |
3757 throw newSQLFeatureNotSupportedException("updateNString"); | |
3758 } | |
3759 | |
3760 @Override | |
3761 public void updateSQLXML(int columnIndex, SQLXML x) throws SQLException { | |
3762 throw newSQLFeatureNotSupportedException("updateSQLXML"); | |
3763 } | |
3764 | |
3765 @Override | |
3766 public void updateSQLXML(String columnLabel, SQLXML x) throws SQLException { | |
3767 throw newSQLFeatureNotSupportedException("updateSQLXML"); | |
3768 } | |
3769 | |
3770 @Override | |
3771 public void updateTime(int columnIndex, Time x) throws SQLException { | |
3772 throw newSQLFeatureNotSupportedException("updateTime"); | |
3773 } | |
3774 | |
3775 @Override | |
3776 public void updateTime(String columnLabel, Time x) throws SQLException { | |
3777 throw newSQLFeatureNotSupportedException("updateTime"); | |
3778 } | |
3779 | |
3780 @Override | |
3781 public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { | |
3782 throw newSQLFeatureNotSupportedException("updateTimestamp"); | |
3783 } | |
3784 | |
3785 @Override | |
3786 public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { | |
3787 throw newSQLFeatureNotSupportedException("updateTimestamp"); | |
3788 } | |
3789 | |
3790 // Chapter 14.2.3.3 Sun JDBC 3.0 Specification | |
3791 /** | |
3792 * Reports whether the last column read had a value of SQL NULL. Note that | |
3793 * you must first call one of the getter methods on a column to try to read | |
3794 * its value and then call the method wasNull to see if the value read was | |
3795 * SQL NULL. | |
3796 * | |
3797 * @return true if the last column value read was SQL NULL and false otherwise | |
3798 */ | |
3799 @Override | |
3800 public boolean wasNull() { | |
3801 return lastReadWasNull; | |
3802 } | |
3803 | |
3804 //== Java 1.7 methods (JDBC 4.1) | |
3805 | |
3806 /** | |
3807 * Retrieves the value of the designated column in the current row | |
3808 * of this ResultSet object and will convert from the SQL type of | |
3809 * the column to the requested Java data type, if the conversion is | |
3810 * supported. If the conversion is not supported or null is | |
3811 * specified for the type, a SQLException is thrown. | |
3812 * | |
3813 * At a minimum, an implementation must support the conversions defined | |
3814 * in Appendix B, Table B-3 and conversion of appropriate user defined | |
3815 * SQL types to a Java type which implements SQLData, or Struct. | |
3816 * Additional conversions may be supported and are vendor defined. | |
3817 * | |
3818 * @param columnIndex the first column is 1, the second is 2, ... | |
3819 * @param type Class representing the Java data type to convert the | |
3820 * designated column to | |
3821 * @return an instance of type holding the column value | |
3822 * @throws SQLException if conversion is not supported, type is | |
3823 * null or another error occurs. The getCause() method of | |
3824 * the exception may provide a more detailed exception, for | |
3825 * example, if a conversion error occurs | |
3826 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
3827 * not support this method | |
3828 */ | |
3829 @Override | |
3830 public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException { | |
3831 checkNotClosed(); | |
3832 if (type == null) | |
3833 throw new SQLException("type is null", "M1M05"); | |
3834 | |
3835 throw newSQLFeatureNotSupportedException("getObject(column, Class<T> type)"); | |
3836 } | |
3837 | |
3838 /** | |
3839 * Retrieves the value of the designated column in the current row | |
3840 * of this ResultSet object and will convert from the SQL type of | |
3841 * the column to the requested Java data type, if the conversion is | |
3842 * supported. If the conversion is not supported or null is | |
3843 * specified for the type, a SQLException is thrown. | |
3844 * | |
3845 * @param columnLabel the label for the column specified with the | |
3846 * SQL AS clause. If the SQL AS clause was not specified, | |
3847 * then the label is the name of the column | |
3848 * @param type Class representing the Java data type to convert the | |
3849 * designated column to | |
3850 * @return an instance of type holding the column value | |
3851 * @throws SQLException if conversion is not supported, type is | |
3852 * null or another error occurs. The getCause() method of | |
3853 * the exception may provide a more detailed exception, for | |
3854 * example, if a conversion error occurs | |
3855 * @throws SQLFeatureNotSupportedException the JDBC driver does | |
3856 * not support this method | |
3857 */ | |
3858 @Override | |
3859 public <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException { | |
3860 return getObject(findColumn(columnLabel), type); | |
3861 } | |
3862 | |
3863 //== Java 1.8 methods (JDBC 4.2) | |
3864 | |
3865 @Override | |
3866 public void updateObject(int columnIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException { | |
3867 throw newSQLFeatureNotSupportedException("updateObject"); | |
3868 } | |
3869 | |
3870 @Override | |
3871 public void updateObject(String columnLabel, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException { | |
3872 throw newSQLFeatureNotSupportedException("updateObject"); | |
3873 } | |
3874 | |
3875 @Override | |
3876 public void updateObject(int columnIndex, Object x, SQLType targetSqlType) throws SQLException { | |
3877 throw newSQLFeatureNotSupportedException("updateObject"); | |
3878 } | |
3879 | |
3880 @Override | |
3881 public void updateObject(String columnLabel, Object x, SQLType targetSqlType) throws SQLException { | |
3882 throw newSQLFeatureNotSupportedException("updateObject"); | |
3883 } | |
3884 | |
3885 //== end methods of interface ResultSet | |
3886 | |
3887 | |
3888 //== internal helper methods which do not belong to the JDBC interface | |
3889 | |
3890 /** | |
3891 * Adds a warning to the pile of warnings this ResultSet object has. If | |
3892 * there were no warnings (or clearWarnings was called) this warning will | |
3893 * be the first, otherwise this warning will get appended to the current | |
3894 * warning. | |
3895 * | |
3896 * @param reason the warning message | |
3897 */ | |
3898 private void addWarning(final String reason, final String sqlstate) { | |
3899 SQLWarning warng = new SQLWarning(reason, sqlstate); | |
3900 if (warnings == null) { | |
3901 warnings = warng; | |
3902 } else { | |
3903 warnings.setNextWarning(warng); | |
3904 } | |
3905 } | |
3906 | |
3907 /** | |
3908 * Local helper method to test whether the ResultSet object is closed | |
3909 * When closed it throws an SQLException | |
3910 */ | |
3911 private void checkNotClosed() throws SQLException { | |
3912 if (isClosed()) | |
3913 throw new SQLException("ResultSet is closed", "M1M20"); | |
3914 } | |
3915 | |
3916 /** | |
3917 * Small helper method that formats the "Invalid Column Index number ..." message | |
3918 * and creates a new SQLDataException object whose SQLState is set | |
3919 * to "22010": invalid indicator parameter value. | |
3920 * | |
3921 * @param colIdx the column index number | |
3922 * @return a new created SQLDataException object with SQLState 22010 | |
3923 */ | |
3924 public static final SQLDataException newSQLInvalidColumnIndexException(final int colIdx) { | |
3925 return new SQLDataException("Invalid Column Index number: " + colIdx, "22010"); | |
3926 } | |
3927 | |
3928 /** | |
3929 * Small helper method that formats the "Could not convert value to a number" message | |
3930 * and creates a new SQLDataException object whose SQLState is set | |
3931 * to "22003": Numeric value out of range. | |
3932 * | |
3933 * @param error the NumberFormatException | |
3934 * @return a new created SQLDataException object with SQLState 22003 | |
3935 */ | |
3936 private static final SQLDataException newSQLNumberFormatException(final NumberFormatException error) { | |
3937 return new SQLDataException("Could not convert value to a number. " + error.getMessage(), "22003"); | |
3938 } | |
3939 } |