1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.jdbc.EmbedResultSet |
4 | |
5 | Copyright 1997, 2005 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.jdbc; |
22 | |
23 | import org.apache.derby.iapi.services.sanity.SanityManager; |
24 | |
25 | import org.apache.derby.iapi.error.StandardException; |
26 | |
27 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
28 | import org.apache.derby.iapi.sql.conn.StatementContext; |
29 | |
30 | import org.apache.derby.iapi.sql.ResultSet; |
31 | import org.apache.derby.iapi.sql.ParameterValueSet; |
32 | import org.apache.derby.iapi.sql.execute.ExecutionFactory; |
33 | import org.apache.derby.iapi.sql.execute.ExecCursorTableReference; |
34 | import org.apache.derby.iapi.sql.execute.ExecRow; |
35 | import org.apache.derby.iapi.sql.execute.NoPutResultSet; |
36 | import org.apache.derby.impl.sql.execute.ScrollInsensitiveResultSet; |
37 | |
38 | import org.apache.derby.iapi.sql.Activation; |
39 | import org.apache.derby.iapi.sql.execute.CursorActivation; |
40 | |
41 | import org.apache.derby.iapi.types.DataValueDescriptor; |
42 | import org.apache.derby.iapi.types.RawToBinaryFormatStream; |
43 | import org.apache.derby.iapi.types.ReaderToUTF8Stream; |
44 | import org.apache.derby.iapi.types.UserDataValue; |
45 | import org.apache.derby.iapi.types.VariableSizeDataValue; |
46 | import org.apache.derby.iapi.sql.ResultDescription; |
47 | import org.apache.derby.iapi.services.io.StreamStorable; |
48 | |
49 | import org.apache.derby.iapi.services.io.LimitInputStream; |
50 | import org.apache.derby.iapi.services.io.NewByteArrayInputStream; |
51 | import org.apache.derby.iapi.services.io.LimitReader; |
52 | import org.apache.derby.iapi.error.ExceptionSeverity; |
53 | import org.apache.derby.iapi.reference.JDBC20Translation; |
54 | import org.apache.derby.iapi.reference.JDBC30Translation; |
55 | import org.apache.derby.iapi.reference.SQLState; |
56 | import org.apache.derby.iapi.util.StringUtil; |
57 | |
58 | /* can't import these due to name overlap: |
59 | import java.sql.ResultSet; |
60 | */ |
61 | import java.sql.Blob; |
62 | import java.sql.Clob; |
63 | import java.sql.Statement; |
64 | import java.sql.SQLException; |
65 | import java.sql.SQLWarning; |
66 | import java.sql.ResultSetMetaData; |
67 | import java.sql.Date; |
68 | import java.sql.Time; |
69 | import java.sql.Timestamp; |
70 | import java.sql.Types; |
71 | |
72 | import java.io.InputStream; |
73 | import java.io.IOException; |
74 | import java.net.URL; |
75 | |
76 | import java.util.Arrays; |
77 | import java.util.Calendar; |
78 | |
79 | /** |
80 | * A EmbedResultSet for results from the EmbedStatement family. |
81 | <P><B>Supports</B> |
82 | <UL> |
83 | <LI> JSR 169 |
84 | </UL> |
85 | * @author ames |
86 | */ |
87 | |
88 | public abstract class EmbedResultSet extends ConnectionChild |
89 | implements java.sql.ResultSet, Comparable { |
90 | |
91 | // cursor movement |
92 | protected static final int FIRST = 1; |
93 | protected static final int NEXT = 2; |
94 | protected static final int LAST = 3; |
95 | protected static final int PREVIOUS = 4; |
96 | protected static final int BEFOREFIRST = 5; |
97 | protected static final int AFTERLAST = 6; |
98 | protected static final int ABSOLUTE = 7; |
99 | protected static final int RELATIVE = 8; |
100 | |
101 | /** |
102 | * The currentRow contains the data of the current row of the resultset. |
103 | * If the containing row array is null, the cursor is not postioned on a |
104 | * row |
105 | */ |
106 | private final ExecRow currentRow; |
107 | protected boolean wasNull; |
108 | |
109 | /** |
110 | * Set if this ResultSet is definitely closed. |
111 | * If the connection has been closed, or the database |
112 | * or system shutdown but the ResultSet has not been |
113 | * closed explictly then this may be false. Once |
114 | * this object detects the connection is closed |
115 | * isClosed will be set to true. |
116 | */ |
117 | boolean isClosed; |
118 | |
119 | private boolean isOnInsertRow; |
120 | private Object currentStream; |
121 | |
122 | // immutable state |
123 | private ResultSet theResults; |
124 | private boolean forMetaData; |
125 | private ResultSetMetaData rMetaData; |
126 | private SQLWarning topWarning; |
127 | |
128 | // This activation is set by EmbedStatement |
129 | // for a single execution Activation. Ie. |
130 | // a ResultSet from a Statement.executeQuery(). |
131 | // In this case the finalization of the ResultSet |
132 | // will mark the Activation as unused. |
133 | // c.f. EmbedPreparedStatement.finalize(). |
134 | Activation finalizeActivation; |
135 | |
136 | // Order of creation |
137 | final int order; |
138 | |
139 | |
140 | private final ResultDescription resultDescription; |
141 | |
142 | // max rows limit for this result set |
143 | private int maxRows; |
144 | // The Maximum field size limt set for this result set |
145 | private final int maxFieldSize; |
146 | |
147 | /* |
148 | * Incase of forward only cursors we limit the number of rows |
149 | * returned if the maxRows is set. The following varible is used |
150 | * to keep the count of number of rows returned to the user. |
151 | */ |
152 | private int NumberofFetchedRows; |
153 | |
154 | |
155 | /** |
156 | * The statement object that originally created us. |
157 | we hang on to the statement to prevent GC from |
158 | closing it under us |
159 | */ |
160 | private final EmbedStatement stmt; |
161 | |
162 | /** |
163 | * The statement that currently owns this ResultSet. |
164 | * Statements created in procedures are passed off |
165 | * to the Statement that called the procedure. |
166 | * This is to avoid the ResultSet being closed |
167 | * due to the Statement within the procedure |
168 | * or the nested Connection being closed. |
169 | */ |
170 | private EmbedStatement owningStmt; |
171 | |
172 | /** |
173 | * Statement object the application used to |
174 | * create this ResultSet. |
175 | */ |
176 | private Statement applicationStmt; |
177 | |
178 | private long timeoutMillis; |
179 | |
180 | private final boolean isAtomic; |
181 | |
182 | private final int concurrencyOfThisResultSet; |
183 | |
184 | /* updateRow is used to keep the values which are updated with updateXXX() |
185 | * calls. It is used by both insertRow() and updateRow(). |
186 | * It is initialized to null if the resultset is not updatable. |
187 | */ |
188 | private final ExecRow updateRow; |
189 | |
190 | /* These are the columns which have been updated so far. |
191 | */ |
192 | private boolean[] columnGotUpdated; |
193 | private boolean currentRowHasBeenUpdated; //Gets set to true after first updateXXX on a row. Gets reset to false when the cursor moves off the row |
194 | |
195 | private int fetchDirection; |
196 | private int fetchSize; |
197 | |
198 | /** |
199 | * Indicates which columns have already been fetched |
200 | * as a stream for a row. Created on-demand by a getXXXStream call. |
201 | */ |
202 | private boolean[] streamUsedFlags; |
203 | |
204 | /** |
205 | * This class provides the glue between the Cloudscape |
206 | * resultset and the JDBC resultset, mapping calls-to-calls. |
207 | */ |
208 | public EmbedResultSet(EmbedConnection conn, ResultSet resultsToWrap, |
209 | boolean forMetaData, EmbedStatement stmt, boolean isAtomic) |
210 | throws SQLException { |
211 | |
212 | super(conn); |
213 | |
214 | if (SanityManager.DEBUG) |
215 | SanityManager.ASSERT(resultsToWrap!=null); |
216 | theResults = resultsToWrap; |
217 | this.forMetaData = forMetaData; |
218 | this.applicationStmt = this.stmt = owningStmt = stmt; |
219 | |
220 | this.timeoutMillis = stmt == null |
221 | ? 0L |
222 | : (long)stmt.getQueryTimeout() * 1000L; |
223 | |
224 | this.isAtomic = isAtomic; |
225 | |
226 | |
227 | //If the Statement object has CONCUR_READ_ONLY set on it then the concurrency on the ResultSet object will be CONCUR_READ_ONLY also. |
228 | //But, if the Statement object has CONCUR_UPDATABLE set on it, then the concurrency on the ResultSet object can be |
229 | //CONCUR_READ_ONLY or CONCUR_UPDATABLE depending on whether the underlying language resultset is updateable or not. |
230 | //If the underlying language resultset is not updateable, then the concurrency of the ResultSet object will be CONCUR_READ_ONLY |
231 | //and a warning will be issued on the ResultSet object. |
232 | if (stmt == null) concurrencyOfThisResultSet = JDBC20Translation.CONCUR_READ_ONLY; |
233 | else if (stmt.getResultSetConcurrency() == JDBC20Translation.CONCUR_READ_ONLY) |
234 | concurrencyOfThisResultSet = JDBC20Translation.CONCUR_READ_ONLY; |
235 | else { |
236 | if (!isForUpdate()) { //language resultset not updatable |
237 | concurrencyOfThisResultSet = JDBC20Translation.CONCUR_READ_ONLY; |
238 | SQLWarning w = StandardException.newWarning(SQLState.QUERY_NOT_QUALIFIED_FOR_UPDATABLE_RESULTSET); |
239 | if (topWarning == null) |
240 | topWarning = w; |
241 | else |
242 | topWarning.setNextWarning(w); |
243 | } else |
244 | concurrencyOfThisResultSet = JDBC20Translation.CONCUR_UPDATABLE; |
245 | } |
246 | |
247 | // Fill in the column types |
248 | resultDescription = theResults.getResultDescription(); |
249 | final ExecutionFactory factory = conn.getLanguageConnection(). |
250 | getLanguageConnectionFactory().getExecutionFactory(); |
251 | final int columnCount = getMetaData().getColumnCount(); |
252 | this.currentRow = factory.getValueRow(columnCount); |
253 | currentRow.setRowArray(null); |
254 | |
255 | // Only incur the cost of allocating and maintaining |
256 | // updated column information if the columns can be updated. |
257 | if (concurrencyOfThisResultSet == JDBC20Translation.CONCUR_UPDATABLE) |
258 | { |
259 | //initialize arrays related to updateRow implementation |
260 | columnGotUpdated = new boolean[columnCount]; |
261 | updateRow = factory.getValueRow(columnCount); |
262 | for (int i = 1; i <= columnCount; i++) { |
263 | updateRow.setColumn(i, resultDescription.getColumnDescriptor(i). |
264 | getType().getNull()); |
265 | } |
266 | initializeUpdateRowModifiers(); |
267 | } else { |
268 | updateRow = null; |
269 | } |
270 | |
271 | // assign the max rows and maxfiled size limit for this result set |
272 | if (stmt != null) |
273 | { |
274 | // At connectivity level we handle only for forward only cursor |
275 | if (stmt.resultSetType == JDBC20Translation.TYPE_FORWARD_ONLY) |
276 | maxRows = stmt.maxRows; |
277 | |
278 | maxFieldSize = stmt.MaxFieldSize; |
279 | } |
280 | else |
281 | maxFieldSize = 0; |
282 | |
283 | order = conn.getResultSetOrderId(); |
284 | } |
285 | |
286 | /** |
287 | JDBC states that a ResultSet is closed when garbage collected. |
288 | We simply mark the activation as unused. Some later use |
289 | of the connection will clean everything up. |
290 | |
291 | @exception Throwable Allows any exception to be thrown during finalize |
292 | */ |
293 | protected void finalize() throws Throwable { |
294 | super.finalize(); |
295 | |
296 | if (finalizeActivation != null) { |
297 | finalizeActivation.markUnused(); |
298 | } |
299 | } |
300 | |
301 | private void checkNotOnInsertRow() throws SQLException { |
302 | if (isOnInsertRow) { |
303 | throw newSQLException(SQLState.NO_CURRENT_ROW); |
304 | } |
305 | } |
306 | |
307 | // checkOnRow protects us from making requests of |
308 | // resultSet that would fail with NullPointerExceptions |
309 | // or milder problems due to not having a row. |
310 | protected final void checkOnRow() throws SQLException |
311 | { |
312 | if (currentRow.getRowArray() == null) { |
313 | throw newSQLException(SQLState.NO_CURRENT_ROW); |
314 | } |
315 | } |
316 | |
317 | /** |
318 | * Initializes the currentRowHasBeenUpdated and columnGotUpdated fields |
319 | */ |
320 | private void initializeUpdateRowModifiers() { |
321 | currentRowHasBeenUpdated = false; |
322 | Arrays.fill(columnGotUpdated, false); |
323 | } |
324 | |
325 | /** |
326 | Check the column is in range *and* return the JDBC type of the column. |
327 | |
328 | @exception SQLException ResultSet is not on a row or columnIndex is out of range. |
329 | */ |
330 | final int getColumnType(int columnIndex) throws SQLException { |
331 | if (!isOnInsertRow) checkOnRow(); // first make sure there's a row |
332 | |
333 | if (columnIndex < 1 || |
334 | columnIndex > resultDescription.getColumnCount()) |
335 | throw newSQLException(SQLState.COLUMN_NOT_FOUND, |
336 | new Integer(columnIndex)); |
337 | |
338 | return resultDescription.getColumnDescriptor(columnIndex).getType().getJDBCTypeId(); |
339 | } |
340 | |
341 | /* |
342 | * java.sql.ResultSet interface |
343 | */ |
344 | /** |
345 | * A ResultSet is initially positioned before its first row; the |
346 | * first call to next makes the first row the current row; the |
347 | * second call makes the second row the current row, etc. |
348 | * |
349 | * <P>If an input stream from the previous row is open, it is |
350 | * implicitly closed. The ResultSet's warning chain is cleared |
351 | * when a new row is read. |
352 | * |
353 | * @return true if the new current row is valid; false if there |
354 | * are no more rows |
355 | * @exception SQLException thrown on failure. |
356 | */ |
357 | public boolean next() throws SQLException |
358 | { |
359 | // we seem to have some trigger paths which don't have |
360 | // statement initialized, may not need this check in those cases |
361 | if (maxRows !=0 ) |
362 | { |
363 | NumberofFetchedRows++; |
364 | // check whether we hit the maxRows limit |
365 | if (NumberofFetchedRows > maxRows) |
366 | { |
367 | //we return false for the next call when maxRows is hit |
368 | closeCurrentStream(); |
369 | return false; |
370 | } |
371 | } |
372 | return movePosition(NEXT, 0, "next"); |
373 | } |
374 | |
375 | protected boolean movePosition(int position, String positionText) |
376 | throws SQLException |
377 | { |
378 | return movePosition(position, 0, positionText); |
379 | } |
380 | |
381 | protected boolean movePosition(int position, int row, String positionText) |
382 | throws SQLException |
383 | { |
384 | closeCurrentStream(); // closing currentStream does not depend on the |
385 | // underlying connection. Do this outside of |
386 | // the connection synchronization. |
387 | |
388 | checkExecIfClosed(positionText); // checking result set closure does not depend |
389 | // on the underlying connection. Do this |
390 | // outside of the connection synchronization. |
391 | |
392 | if (isOnInsertRow) { |
393 | moveToCurrentRow(); |
394 | } |
395 | |
396 | |
397 | synchronized (getConnectionSynchronization()) { |
398 | |
399 | setupContextStack(); |
400 | try { |
401 | LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection(); |
402 | final ExecRow newRow; |
403 | try { |
404 | |
405 | /* Push and pop a StatementContext around a next call |
406 | * so that the ResultSet will get correctly closed down |
407 | * on an error. |
408 | * (Cache the LanguageConnectionContext) |
409 | */ |
410 | StatementContext statementContext = |
411 | lcc.pushStatementContext(isAtomic, |
412 | concurrencyOfThisResultSet==JDBC20Translation.CONCUR_READ_ONLY, |
413 | getSQLText(), |
414 | getParameterValueSet(), |
415 | false, timeoutMillis); |
416 | |
417 | switch (position) |
418 | { |
419 | case BEFOREFIRST: |
420 | newRow = theResults.setBeforeFirstRow(); |
421 | break; |
422 | |
423 | case FIRST: |
424 | newRow = theResults.getFirstRow(); |
425 | break; |
426 | |
427 | case NEXT: |
428 | newRow = theResults.getNextRow(); |
429 | break; |
430 | |
431 | case LAST: |
432 | newRow = theResults.getLastRow(); |
433 | break; |
434 | |
435 | case AFTERLAST: |
436 | newRow = theResults.setAfterLastRow(); |
437 | break; |
438 | |
439 | case PREVIOUS: |
440 | newRow = theResults.getPreviousRow(); |
441 | break; |
442 | |
443 | case ABSOLUTE: |
444 | newRow = theResults.getAbsoluteRow(row); |
445 | break; |
446 | |
447 | case RELATIVE: |
448 | newRow = theResults.getRelativeRow(row); |
449 | break; |
450 | |
451 | default: |
452 | newRow = null; |
453 | if (SanityManager.DEBUG) |
454 | { |
455 | SanityManager.THROWASSERT( |
456 | "Unexpected value for position - " + position); |
457 | } |
458 | } |
459 | |
460 | lcc.popStatementContext(statementContext, null); |
461 | |
462 | } catch (Throwable t) { |
463 | /* |
464 | * Need to close the result set here because the error might |
465 | * cause us to lose the current connection if this is an XA |
466 | * connection and we won't be able to do the close later |
467 | */ |
468 | throw closeOnTransactionError(t); |
469 | } |
470 | |
471 | SQLWarning w = theResults.getWarnings(); |
472 | if (w != null) { |
473 | if (topWarning == null) |
474 | topWarning = w; |
475 | else |
476 | topWarning.setNextWarning(w); |
477 | } |
478 | |
479 | boolean onRow = (newRow!=null); |
480 | if (onRow) { |
481 | currentRow.setRowArray(newRow.getRowArray()); |
482 | } else { |
483 | currentRow.setRowArray(null); |
484 | } |
485 | |
486 | |
487 | //if (onRow && !(currentRow instanceof org.apache.derby.impl.sql.execute.ValueRow)) |
488 | // System.out.println(currentRow.getClass()); |
489 | |
490 | // The ResultSet may implicitly close when when the ResultSet type |
491 | // is TYPE_FORWARD_ONLY and the next method of ResultSet returns |
492 | // false. This will cause a commit if autocommit = true. |
493 | if (!onRow && (position == NEXT)) { |
494 | |
495 | // In case of resultset for MetaData, we will only commit |
496 | // if we are the only statement currently opened for this |
497 | // connection; otherwise we don't want to affect other |
498 | // resultSet's by committing the MetaData one. |
499 | // There is no internal xact (xact isolation) for MetaData type |
500 | // of resultSet; therefore committing (to release locks) would end |
501 | // up committing all the other resultSet for this connection. |
502 | // |
503 | // We do synchronize on the connection, therefore Activation count |
504 | // should be valid and protected. |
505 | // |
506 | //LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection(); |
507 | if (forMetaData && (lcc.getActivationCount() > 1)) { |
508 | // we do not want to commit here as there seems to be other |
509 | // statements/resultSets currently opened for this connection. |
510 | } else if (owningStmt != null && |
511 | owningStmt.getResultSetType() == TYPE_FORWARD_ONLY) { |
512 | // allow the satement to commit if required. |
513 | owningStmt.resultSetClosing(this); |
514 | } |
515 | } |
516 | |
517 | // Clear the indication of which columns were fetched as streams. |
518 | if (streamUsedFlags != null) |
519 | Arrays.fill(streamUsedFlags, false); |
520 | if (columnGotUpdated != null && currentRowHasBeenUpdated) { |
521 | initializeUpdateRowModifiers(); |
522 | } |
523 | |
524 | return onRow; |
525 | } finally { |
526 | restoreContextStack(); |
527 | } |
528 | } |
529 | |
530 | } |
531 | |
532 | |
533 | |
534 | |
535 | /** |
536 | * In some cases, it is desirable to immediately release a |
537 | * ResultSet's database and JDBC resources instead of waiting for |
538 | * this to happen when it is automatically closed; the close |
539 | * method provides this immediate release. |
540 | * |
541 | * <P><B>Note:</B> A ResultSet is automatically closed by the |
542 | * Statement that generated it when that Statement is closed, |
543 | * re-executed, or is used to retrieve the next result from a |
544 | * sequence of multiple results. A ResultSet is also automatically |
545 | * closed when it is garbage collected. |
546 | * @exception SQLException thrown on failure. |
547 | */ |
548 | public void close() throws SQLException { |
549 | |
550 | /* if this result is already closed, don't try to close again |
551 | * we may have closed it earlier because of an error and trying |
552 | * to close again will cause a different problem if the connection |
553 | * has been closed as in XA error handling |
554 | */ |
555 | if (isClosed) |
556 | return; |
557 | |
558 | closeCurrentStream(); // closing currentStream does not depend on the |
559 | // underlying connection. Do this outside of |
560 | // the connection synchronization. |
561 | // Would like to throw an exception if already closed, but |
562 | // some code assumes you can close a ResultSet more than once. |
563 | // checkIfClosed("close"); |
564 | |
565 | // synchronize out here so the close and the autocommit are |
566 | // both in the same sync block. |
567 | synchronized (getConnectionSynchronization()) { |
568 | |
569 | try { |
570 | setupContextStack(); // make sure there's context |
571 | } catch (SQLException se) { |
572 | // we may get an exception here if this is part of an XA transaction |
573 | // and the transaction has been committed |
574 | // just give up and return |
575 | return; |
576 | } |
577 | |
578 | try { |
579 | try { |
580 | theResults.finish(); // release the result set, don't just close it |
581 | } catch (Throwable t) { |
582 | throw handleException(t); |
583 | } |
584 | |
585 | // In case of resultset for MetaData, we will only commit |
586 | // if we are the only statement currently opened for this |
587 | // connection; otherwise we don't want to affect other |
588 | // resultSet's by committing the MetaData one. |
589 | // There is no internal xact (xact isolation) for MetaData type |
590 | // of resultSet; therefore committing (to release locks) would end |
591 | // up committing all the other resultSet for this connection. |
592 | // |
593 | // We do synchronize on the connection, therefore Activation count |
594 | // should be valid and protected. |
595 | // |
596 | if (forMetaData) { |
597 | |
598 | LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection(); |
599 | if (lcc.getActivationCount() > 1) { |
600 | // we do not want to commit here as there seems to be other |
601 | // statements/resultSets currently opened for this connection. |
602 | } else if (owningStmt != null) |
603 | // allow the satement to commit if required. |
604 | owningStmt.resultSetClosing(this); |
605 | |
606 | } else if (owningStmt != null) { |
607 | // allow the satement to commit if required. |
608 | owningStmt.resultSetClosing(this); |
609 | } |
610 | |
611 | } finally { |
612 | isClosed = true; |
613 | restoreContextStack(); |
614 | } |
615 | |
616 | // the idea is to release resources, so: |
617 | currentRow.setRowArray(null); |
618 | rMetaData = null; // let it go, we can make a new one |
619 | |
620 | // we hang on to theResults and messenger |
621 | // in case more calls come in on this resultSet |
622 | } |
623 | |
624 | } |
625 | |
626 | /** |
627 | * A column may have the value of SQL NULL; wasNull reports whether |
628 | * the last column read had this special value. |
629 | * Note that you must first call getXXX on a column to try to read |
630 | * its value and then call wasNull() to find if the value was |
631 | * the SQL NULL. |
632 | * |
633 | * <p> we take the least exception approach and simply return false |
634 | * if no column has been read yet. |
635 | * |
636 | * @return true if last column read was SQL NULL |
637 | * |
638 | * @exception SQLException Thrown if this ResultSet is closed |
639 | */ |
640 | public final boolean wasNull() throws SQLException { |
641 | checkIfClosed("wasNull"); |
642 | return wasNull; |
643 | } |
644 | |
645 | //====================================================================== |
646 | // Methods for accessing results by column index |
647 | //====================================================================== |
648 | |
649 | /** |
650 | * Get the value of a column in the current row as a Java String. |
651 | * |
652 | * @param columnIndex the first column is 1, the second is 2, ... |
653 | * @return the column value; if the value is SQL NULL, the result is null |
654 | * @exception SQLException thrown on failure. |
655 | */ |
656 | public final String getString(int columnIndex) throws SQLException { |
657 | checkIfClosed("getString"); |
658 | |
659 | try { |
660 | |
661 | DataValueDescriptor dvd = getColumn(columnIndex); |
662 | |
663 | if (wasNull = dvd.isNull()) |
664 | return null; |
665 | |
666 | String value = dvd.getString(); |
667 | |
668 | // check for the max field size limit |
669 | if (maxFieldSize > 0 && isMaxFieldSizeType(getColumnType(columnIndex))) |
670 | { |
671 | if (value.length() > maxFieldSize ) |
672 | { |
673 | value = value.substring(0, maxFieldSize); |
674 | } |
675 | } |
676 | |
677 | return value; |
678 | |
679 | } catch (Throwable t) { |
680 | throw noStateChangeException(t); |
681 | } |
682 | } |
683 | |
684 | /** |
685 | * Get the value of a column in the current row as a Java boolean. |
686 | * |
687 | * @param columnIndex the first column is 1, the second is 2, ... |
688 | * @return the column value; if the value is SQL NULL, the result is false |
689 | * @exception SQLException thrown on failure. |
690 | */ |
691 | public final boolean getBoolean(int columnIndex) throws SQLException { |
692 | checkIfClosed("getBoolean"); |
693 | |
694 | try { |
695 | |
696 | DataValueDescriptor dvd = getColumn(columnIndex); |
697 | |
698 | if (wasNull = dvd.isNull()) |
699 | return false; |
700 | |
701 | return dvd.getBoolean(); |
702 | |
703 | } catch (StandardException t) { |
704 | throw noStateChangeException(t); |
705 | } |
706 | } |
707 | |
708 | /** |
709 | * Get the value of a column in the current row as a Java byte. |
710 | * |
711 | * @param columnIndex the first column is 1, the second is 2, ... |
712 | * @return the column value; if the value is SQL NULL, the result is 0 |
713 | * @exception SQLException thrown on failure. |
714 | */ |
715 | public final byte getByte(int columnIndex) throws SQLException { |
716 | checkIfClosed("getByte"); |
717 | try { |
718 | |
719 | DataValueDescriptor dvd = getColumn(columnIndex); |
720 | |
721 | if (wasNull = dvd.isNull()) |
722 | return 0; |
723 | |
724 | return dvd.getByte(); |
725 | |
726 | } catch (StandardException t) { |
727 | throw noStateChangeException(t); |
728 | } |
729 | } |
730 | |
731 | /** |
732 | * Get the value of a column in the current row as a Java short. |
733 | * |
734 | * @param columnIndex the first column is 1, the second is 2, ... |
735 | * @return the column value; if the value is SQL NULL, the result is 0 |
736 | * @exception SQLException thrown on failure. |
737 | */ |
738 | public final short getShort(int columnIndex) throws SQLException { |
739 | checkIfClosed("getShort"); |
740 | |
741 | try { |
742 | |
743 | DataValueDescriptor dvd = getColumn(columnIndex); |
744 | |
745 | if (wasNull = dvd.isNull()) |
746 | return 0; |
747 | |
748 | return dvd.getShort(); |
749 | |
750 | } catch (StandardException t) { |
751 | throw noStateChangeException(t); |
752 | } |
753 | } |
754 | |
755 | /** |
756 | * Get the value of a column in the current row as a Java int. |
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 result is 0 |
760 | * @exception SQLException thrown on failure. |
761 | */ |
762 | public final int getInt(int columnIndex) throws SQLException { |
763 | checkIfClosed("getInt"); |
764 | try { |
765 | |
766 | DataValueDescriptor dvd = getColumn(columnIndex); |
767 | |
768 | if (wasNull = dvd.isNull()) |
769 | return 0; |
770 | |
771 | return dvd.getInt(); |
772 | |
773 | } catch (StandardException t) { |
774 | throw noStateChangeException(t); |
775 | } |
776 | } |
777 | |
778 | /** |
779 | * Get the value of a column in the current row as a Java long. |
780 | * |
781 | * @param columnIndex the first column is 1, the second is 2, ... |
782 | * @return the column value; if the value is SQL NULL, the result is 0 |
783 | * @exception SQLException thrown on failure. |
784 | */ |
785 | public final long getLong(int columnIndex) throws SQLException { |
786 | checkIfClosed("getLong"); |
787 | try { |
788 | |
789 | DataValueDescriptor dvd = getColumn(columnIndex); |
790 | |
791 | if (wasNull = dvd.isNull()) |
792 | return 0; |
793 | |
794 | return dvd.getLong(); |
795 | |
796 | } catch (StandardException t) { |
797 | throw noStateChangeException(t); |
798 | } |
799 | } |
800 | |
801 | /** |
802 | * Get the value of a column in the current row as a Java float. |
803 | * |
804 | * @param columnIndex the first column is 1, the second is 2, ... |
805 | * @return the column value; if the value is SQL NULL, the result is 0 |
806 | * @exception SQLException thrown on failure. |
807 | */ |
808 | public final float getFloat(int columnIndex) throws SQLException { |
809 | checkIfClosed("getFloat"); |
810 | try { |
811 | |
812 | DataValueDescriptor dvd = getColumn(columnIndex); |
813 | |
814 | if (wasNull = dvd.isNull()) |
815 | return 0.0F; |
816 | |
817 | return dvd.getFloat(); |
818 | |
819 | } catch (StandardException t) { |
820 | throw noStateChangeException(t); |
821 | } |
822 | } |
823 | |
824 | /** |
825 | * Get the value of a column in the current row as a Java double. |
826 | * |
827 | * @param columnIndex the first column is 1, the second is 2, ... |
828 | * @return the column value; if the value is SQL NULL, the result is 0 |
829 | * @exception SQLException thrown on failure. |
830 | */ |
831 | public final double getDouble(int columnIndex) throws SQLException { |
832 | checkIfClosed("getDouble"); |
833 | try { |
834 | |
835 | DataValueDescriptor dvd = getColumn(columnIndex); |
836 | |
837 | if (wasNull = dvd.isNull()) |
838 | return 0.0; |
839 | |
840 | return dvd.getDouble(); |
841 | |
842 | } catch (StandardException t) { |
843 | throw noStateChangeException(t); |
844 | } |
845 | } |
846 | |
847 | /** |
848 | * Get the value of a column in the current row as a Java byte array. |
849 | * The bytes represent the raw values returned by the driver. |
850 | * |
851 | * @param columnIndex the first column is 1, the second is 2, ... |
852 | * @return the column value; if the value is SQL NULL, the result is null |
853 | * @exception SQLException thrown on failure. |
854 | */ |
855 | public final byte[] getBytes(int columnIndex) throws SQLException { |
856 | checkIfClosed("getBytes"); |
857 | try { |
858 | |
859 | DataValueDescriptor dvd = getColumn(columnIndex); |
860 | |
861 | if (wasNull = dvd.isNull()) |
862 | return null; |
863 | |
864 | byte[] value = dvd.getBytes(); |
865 | |
866 | // check for the max field size limit |
867 | if (maxFieldSize > 0 && isMaxFieldSizeType(getColumnType(columnIndex))) |
868 | { |
869 | if (value.length > maxFieldSize) |
870 | { |
871 | byte [] limited_value = new byte[maxFieldSize]; |
872 | System.arraycopy(value, 0, limited_value, |
873 | 0 , maxFieldSize); |
874 | value = limited_value; |
875 | } |
876 | } |
877 | |
878 | return value; |
879 | |
880 | } catch (StandardException t) { |
881 | throw noStateChangeException(t); |
882 | } |
883 | } |
884 | |
885 | /** |
886 | * Get the value of a column in the current row as a java.sql.Date object. |
887 | * |
888 | * @param columnIndex the first column is 1, the second is 2, ... |
889 | * @return the column value; if the value is SQL NULL, the result is null |
890 | * @exception SQLException thrown on failure. |
891 | */ |
892 | public final Date getDate(int columnIndex) throws SQLException { |
893 | return getDate( columnIndex, (Calendar) null); |
894 | } |
895 | |
896 | /** |
897 | * Get the value of a column in the current row as a java.sql.Time object. |
898 | * |
899 | * @param columnIndex the first column is 1, the second is 2, ... |
900 | * @return the column value; if the value is SQL NULL, the result is null |
901 | * @exception SQLException thrown on failure. |
902 | */ |
903 | public final Time getTime(int columnIndex) throws SQLException { |
904 | return getTime( columnIndex, (Calendar) null); |
905 | } |
906 | |
907 | /** |
908 | * Get the value of a column in the current row as a java.sql.Timestamp object. |
909 | * |
910 | * @param columnIndex the first column is 1, the second is 2, ... |
911 | * @return the column value; if the value is SQL NULL, the result is null |
912 | * @exception SQLException thrown on failure. |
913 | */ |
914 | public final Timestamp getTimestamp(int columnIndex) throws SQLException { |
915 | return getTimestamp( columnIndex, (Calendar) null); |
916 | } |
917 | |
918 | /** |
919 | * JDBC 2.0 |
920 | * |
921 | * Get the value of a column in the current row as a java.sql.Date |
922 | * object. Use the calendar to construct an appropriate millisecond |
923 | * value for the Date, if the underlying database doesn't store |
924 | * timezone information. |
925 | * |
926 | * @param columnIndex the first column is 1, the second is 2, ... |
927 | * @param cal the calendar to use in constructing the date |
928 | * @return the column value; if the value is SQL NULL, the result is null |
929 | * @exception SQLException if a database-access error occurs. |
930 | */ |
931 | public java.sql.Date getDate(int columnIndex, Calendar cal) |
932 | throws SQLException |
933 | { |
934 | checkIfClosed("getDate"); |
935 | try { |
936 | |
937 | DataValueDescriptor dvd = getColumn(columnIndex); |
938 | |
939 | if (wasNull = dvd.isNull()) |
940 | return null; |
941 | |
942 | if( cal == null) |
943 | cal = getCal(); |
944 | |
945 | return dvd.getDate( cal); |
946 | |
947 | } catch (StandardException t) { |
948 | throw noStateChangeException(t); |
949 | } |
950 | } |
951 | |
952 | /** |
953 | * JDBC 2.0 |
954 | * |
955 | * Get the value of a column in the current row as a java.sql.Date |
956 | * object. Use the calendar to construct an appropriate millisecond |
957 | * value for the Date, if the underlying database doesn't store |
958 | * timezone information. |
959 | * |
960 | * @param columnName is the SQL name of the column |
961 | * @param cal the calendar to use in constructing the date |
962 | * @return the column value; if the value is SQL NULL, the result is null |
963 | * @exception SQLException if a database-access error occurs. |
964 | */ |
965 | public java.sql.Date getDate(String columnName, Calendar cal) |
966 | throws SQLException |
967 | { |
968 | checkIfClosed("getDate"); |
969 | return getDate( findColumnName(columnName), cal); |
970 | } |
971 | |
972 | /** |
973 | * JDBC 2.0 |
974 | * |
975 | * Get the value of a column in the current row as a java.sql.Time |
976 | * object. Use the calendar to construct an appropriate millisecond |
977 | * value for the Time, if the underlying database doesn't store |
978 | * timezone information. |
979 | * |
980 | * @param columnIndex the first column is 1, the second is 2, ... |
981 | * @param cal the calendar to use in constructing the time |
982 | * @return the column value; if the value is SQL NULL, the result is null |
983 | * @exception SQLException if a database-access error occurs. |
984 | */ |
985 | public java.sql.Time getTime(int columnIndex, Calendar cal) |
986 | throws SQLException |
987 | { |
988 | checkIfClosed("getTime"); |
989 | try { |
990 | |
991 | DataValueDescriptor dvd = getColumn(columnIndex); |
992 | |
993 | if (wasNull = dvd.isNull()) |
994 | return null; |
995 | |
996 | if( cal == null) |
997 | cal = getCal(); |
998 | return dvd.getTime( cal); |
999 | |
1000 | } catch (StandardException t) { |
1001 | throw noStateChangeException(t); |
1002 | } |
1003 | } |
1004 | |
1005 | /** |
1006 | * JDBC 2.0 |
1007 | * |
1008 | * Get the value of a column in the current row as a java.sql.Time |
1009 | * object. Use the calendar to construct an appropriate millisecond |
1010 | * value for the Time, if the underlying database doesn't store |
1011 | * timezone information. |
1012 | * |
1013 | * @param columnName is the SQL name of the column |
1014 | * @param cal the calendar to use in constructing the time |
1015 | * @return the column value; if the value is SQL NULL, the result is null |
1016 | * @exception SQLException if a database-access error occurs. |
1017 | */ |
1018 | public java.sql.Time getTime(String columnName, Calendar cal) |
1019 | throws SQLException |
1020 | { |
1021 | checkIfClosed("getTime"); |
1022 | return getTime( findColumnName( columnName), cal); |
1023 | } |
1024 | |
1025 | /** |
1026 | * JDBC 2.0 |
1027 | * |
1028 | * Get the value of a column in the current row as a java.sql.Timestamp |
1029 | * object. Use the calendar to construct an appropriate millisecond |
1030 | * value for the Timestamp, if the underlying database doesn't store |
1031 | * timezone information. |
1032 | * |
1033 | * @param columnName is the SQL name of the column |
1034 | * @param cal the calendar to use in constructing the timestamp |
1035 | * @return the column value; if the value is SQL NULL, the result is null |
1036 | * @exception SQLException if a database-access error occurs. |
1037 | */ |
1038 | public java.sql.Timestamp getTimestamp(String columnName, Calendar cal) |
1039 | throws SQLException |
1040 | { |
1041 | checkIfClosed("getTimestamp"); |
1042 | return getTimestamp(findColumnName(columnName), cal); |
1043 | } |
1044 | |
1045 | /** |
1046 | * JDBC 2.0 |
1047 | * |
1048 | * Get the value of a column in the current row as a java.sql.Timestamp |
1049 | * object. Use the calendar to construct an appropriate millisecond |
1050 | * value for the Timestamp, if the underlying database doesn't store |
1051 | * timezone information. |
1052 | * |
1053 | * @param columnIndex the first column is 1, the second is 2, ... |
1054 | * @param cal the calendar to use in constructing the timestamp |
1055 | * @return the column value; if the value is SQL NULL, the result is null |
1056 | * @exception SQLException if a database-access error occurs. |
1057 | */ |
1058 | public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal) |
1059 | throws SQLException |
1060 | { |
1061 | checkIfClosed("getTimestamp"); |
1062 | try { |
1063 | |
1064 | DataValueDescriptor dvd = getColumn(columnIndex); |
1065 | |
1066 | if (wasNull = dvd.isNull()) |
1067 | return null; |
1068 | |
1069 | if( cal == null) |
1070 | cal = getCal(); |
1071 | return dvd.getTimestamp( cal); |
1072 | |
1073 | } catch (StandardException t) { |
1074 | throw noStateChangeException(t); |
1075 | } |
1076 | } |
1077 | |
1078 | /** |
1079 | * JDBC 2.0 |
1080 | * |
1081 | * <p>Get the value of a column in the current row as a java.io.Reader. |
1082 | * |
1083 | * @exception SQLException database error. |
1084 | */ |
1085 | public final java.io.Reader getCharacterStream(int columnIndex) |
1086 | throws SQLException |
1087 | { |
1088 | checkIfClosed("getCharacterStream"); |
1089 | int lmfs; |
1090 | int colType = getColumnType(columnIndex); |
1091 | switch (colType) { |
1092 | case Types.CHAR: |
1093 | case Types.VARCHAR: |
1094 | case Types.LONGVARCHAR: |
1095 | lmfs = maxFieldSize; |
1096 | break; |
1097 | case Types.CLOB: // Embedded and JCC extension - CLOB is not subject to max field size. |
1098 | lmfs = 0; |
1099 | break; |
1100 | |
1101 | // JDBC says to support these, but no defintion exists for the output. |
1102 | // match JCC which treats the bytes as a UTF16-BE stream |
1103 | case Types.BINARY: |
1104 | case Types.VARBINARY: |
1105 | case Types.LONGVARBINARY: |
1106 | case Types.BLOB: |
1107 | try { |
1108 | java.io.InputStream is = getBinaryStream(columnIndex); |
1109 | if (is == null) |
1110 | return null; |
1111 | java.io.Reader r = new java.io.InputStreamReader(is, "UTF-16BE"); |
1112 | currentStream = r; |
1113 | return r; |
1114 | } catch (java.io.UnsupportedEncodingException uee) { |
1115 | throw new SQLException(uee.getMessage()); |
1116 | } |
1117 | default: |
1118 | throw dataTypeConversion("java.io.Reader", columnIndex); |
1119 | } |
1120 | |
1121 | Object syncLock = getConnectionSynchronization(); |
1122 | |
1123 | synchronized (syncLock) { |
1124 | |
1125 | boolean pushStack = false; |
1126 | try { |
1127 | |
1128 | useStream(columnIndex); |
1129 | |
1130 | DataValueDescriptor dvd = getColumn(columnIndex); |
1131 | |
1132 | if (wasNull = dvd.isNull()) { return null; } |
1133 | |
1134 | pushStack = true; |
1135 | setupContextStack(); |
1136 | |
1137 | StreamStorable ss = (StreamStorable) dvd; |
1138 | |
1139 | InputStream stream = ss.returnStream(); |
1140 | |
1141 | if (stream == null) { |
1142 | |
1143 | String val = dvd.getString(); |
1144 | if (lmfs > 0) { |
1145 | if (val.length() > lmfs) |
1146 | val = val.substring(0, lmfs); |
1147 | } |
1148 | java.io.Reader ret = new java.io.StringReader(val); |
1149 | currentStream = ret; |
1150 | return ret; |
1151 | } |
1152 | |
1153 | java.io.Reader ret = new UTF8Reader(stream, lmfs, this, syncLock); |
1154 | currentStream = ret; |
1155 | return ret; |
1156 | |
1157 | } catch (Throwable t) { |
1158 | throw noStateChangeException(t); |
1159 | } finally { |
1160 | if (pushStack) { restoreContextStack(); } |
1161 | } |
1162 | } |
1163 | } |
1164 | |
1165 | /** |
1166 | Pushes a converter on top of getCharacterStream(). |
1167 | * |
1168 | * @param columnIndex the first column is 1, the second is 2, ... |
1169 | * @return a Java input stream that delivers the database column value |
1170 | * as a stream of one byte ASCII characters. If the value is SQL NULL |
1171 | * then the result is null. |
1172 | * @exception SQLException thrown on failure. |
1173 | */ |
1174 | public final InputStream getAsciiStream(int columnIndex) throws SQLException { |
1175 | checkIfClosed("getAsciiStream"); |
1176 | int colType = getColumnType(columnIndex); |
1177 | switch (colType) { |
1178 | case Types.CHAR: |
1179 | case Types.VARCHAR: |
1180 | case Types.LONGVARCHAR: |
1181 | case Types.CLOB: // Embedded and JCC extension |
1182 | break; |
1183 | |
1184 | // JDBC says to support these, we match JCC by returning the raw bytes. |
1185 | case Types.BINARY: |
1186 | case Types.VARBINARY: |
1187 | case Types.LONGVARBINARY: |
1188 | case Types.BLOB: |
1189 | return getBinaryStream(columnIndex); |
1190 | |
1191 | default: |
1192 | throw dataTypeConversion("java.io.InputStream(ASCII)", columnIndex); |
1193 | } |
1194 | |
1195 | java.io.Reader reader = getCharacterStream(columnIndex); |
1196 | if (reader == null) |
1197 | return null; |
1198 | |
1199 | return new ReaderToAscii(reader); |
1200 | } |
1201 | |
1202 | /** |
1203 | * Get the column as an InputStream. If the column is already of type |
1204 | InputStream then just return it, otherwise convert the column to a set |
1205 | of bytes and create a stream out of the bytes. |
1206 | * |
1207 | * @param columnIndex the first column is 1, the second is 2, ... |
1208 | * @return a Java input stream that delivers the database column value |
1209 | * as a stream of uninterpreted bytes. If the value is SQL NULL |
1210 | * then the result is null. |
1211 | * @exception SQLException thrown on failure. |
1212 | */ |
1213 | public final InputStream getBinaryStream(int columnIndex) throws SQLException { |
1214 | checkIfClosed("getBinaryStream"); |
1215 | int lmfs; |
1216 | int colType = getColumnType(columnIndex); |
1217 | switch (colType) { |
1218 | case Types.BINARY: |
1219 | case Types.VARBINARY: |
1220 | case Types.LONGVARBINARY: |
1221 | lmfs = maxFieldSize; |
1222 | break; |
1223 | case Types.BLOB: |
1224 | lmfs = 0; |
1225 | break; |
1226 | |
1227 | default: |
1228 | throw dataTypeConversion("java.io.InputStream", columnIndex); |
1229 | } |
1230 | |
1231 | Object syncLock = getConnectionSynchronization(); |
1232 | |
1233 | synchronized (syncLock) { |
1234 | |
1235 | boolean pushStack = false; |
1236 | try { |
1237 | |
1238 | useStream(columnIndex); |
1239 | |
1240 | DataValueDescriptor dvd = getColumn(columnIndex); |
1241 | |
1242 | if (wasNull = dvd.isNull()) { return null; } |
1243 | |
1244 | pushStack = true; |
1245 | setupContextStack(); |
1246 | |
1247 | StreamStorable ss = (StreamStorable) dvd; |
1248 | |
1249 | InputStream stream = ss.returnStream(); |
1250 | |
1251 | if (stream == null) |
1252 | { |
1253 | stream = new NewByteArrayInputStream(dvd.getBytes()); |
1254 | } else |
1255 | { |
1256 | stream = new BinaryToRawStream(stream, dvd); |
1257 | } |
1258 | |
1259 | if (lmfs > 0) |
1260 | { |
1261 | // Just wrap the InputStream with a LimitInputStream class |
1262 | LimitInputStream limitResultIn = new LimitInputStream(stream); |
1263 | limitResultIn.setLimit(lmfs); |
1264 | stream = limitResultIn; |
1265 | } |
1266 | currentStream = stream; |
1267 | return stream; |
1268 | |
1269 | } catch (Throwable t) { |
1270 | throw noStateChangeException(t); |
1271 | } finally { |
1272 | if (pushStack) { restoreContextStack(); } |
1273 | } |
1274 | } |
1275 | } |
1276 | |
1277 | //====================================================================== |
1278 | // Methods for accessing results by column name |
1279 | //====================================================================== |
1280 | |
1281 | |
1282 | /** |
1283 | * Get the value of a column in the current row as a Java String. |
1284 | * |
1285 | * @param columnName is the SQL name of the column |
1286 | * @return the column value; if the value is SQL NULL, the result is null |
1287 | * @exception SQLException thrown on failure. |
1288 | */ |
1289 | public final String getString(String columnName) throws SQLException { |
1290 | checkIfClosed("getString"); |
1291 | return (getString(findColumnName(columnName))); |
1292 | } |
1293 | |
1294 | /** |
1295 | * Get the value of a column in the current row as a Java boolean. |
1296 | * |
1297 | * @param columnName is the SQL name of the column |
1298 | * @return the column value; if the value is SQL NULL, the result is false |
1299 | * @exception SQLException thrown on failure. |
1300 | */ |
1301 | public final boolean getBoolean(String columnName) throws SQLException { |
1302 | checkIfClosed("getBoolean"); |
1303 | return (getBoolean(findColumnName(columnName))); |
1304 | } |
1305 | |
1306 | /** |
1307 | * Get the value of a column in the current row as a Java byte. |
1308 | * |
1309 | * @param columnName is the SQL name of the column |
1310 | * @return the column value; if the value is SQL NULL, the result is 0 |
1311 | * @exception SQLException thrown on failure. |
1312 | */ |
1313 | public final byte getByte(String columnName) throws SQLException { |
1314 | checkIfClosed("getByte"); |
1315 | return (getByte(findColumnName(columnName))); |
1316 | } |
1317 | |
1318 | /** |
1319 | * Get the value of a column in the current row as a Java short. |
1320 | * |
1321 | * @param columnName is the SQL name of the column |
1322 | * @return the column value; if the value is SQL NULL, the result is 0 |
1323 | * @exception SQLException thrown on failure. |
1324 | */ |
1325 | public final short getShort(String columnName) throws SQLException { |
1326 | checkIfClosed("getShort"); |
1327 | return (getShort(findColumnName(columnName))); |
1328 | } |
1329 | |
1330 | /** |
1331 | * Get the value of a column in the current row as a Java int. |
1332 | * |
1333 | * @param columnName is the SQL name of the column |
1334 | * @return the column value; if the value is SQL NULL, the result is 0 |
1335 | * @exception SQLException thrown on failure. |
1336 | */ |
1337 | public final int getInt(String columnName) throws SQLException { |
1338 | checkIfClosed("getInt"); |
1339 | return (getInt(findColumnName(columnName))); |
1340 | } |
1341 | |
1342 | /** |
1343 | * Get the value of a column in the current row as a Java long. |
1344 | * |
1345 | * @param columnName is the SQL name of the column |
1346 | * @return the column value; if the value is SQL NULL, the result is 0 |
1347 | * @exception SQLException thrown on failure. |
1348 | */ |
1349 | public final long getLong(String columnName) throws SQLException { |
1350 | checkIfClosed("getLong"); |
1351 | return (getLong(findColumnName(columnName))); |
1352 | } |
1353 | |
1354 | /** |
1355 | * Get the value of a column in the current row as a Java float. |
1356 | * |
1357 | * @param columnName is the SQL name of the column |
1358 | * @return the column value; if the value is SQL NULL, the result is 0 |
1359 | * @exception SQLException thrown on failure. |
1360 | */ |
1361 | public final float getFloat(String columnName) throws SQLException { |
1362 | checkIfClosed("getFloat"); |
1363 | return (getFloat(findColumnName(columnName))); |
1364 | } |
1365 | |
1366 | /** |
1367 | * Get the value of a column in the current row as a Java double. |
1368 | * |
1369 | * @param columnName is the SQL name of the column |
1370 | * @return the column value; if the value is SQL NULL, the result is 0 |
1371 | * @exception SQLException thrown on failure. |
1372 | */ |
1373 | public final double getDouble(String columnName) throws SQLException { |
1374 | checkIfClosed("getDouble"); |
1375 | return (getDouble(findColumnName(columnName))); |
1376 | } |
1377 | |
1378 | /** |
1379 | * Get the value of a column in the current row as a Java byte array. |
1380 | * The bytes represent the raw values returned by the driver. |
1381 | * |
1382 | * @param columnName is the SQL name of the column |
1383 | * @return the column value; if the value is SQL NULL, the result is null |
1384 | * @exception SQLException thrown on failure. |
1385 | */ |
1386 | public final byte[] getBytes(String columnName) throws SQLException { |
1387 | checkIfClosed("getBytes"); |
1388 | return (getBytes(findColumnName(columnName))); |
1389 | } |
1390 | |
1391 | /** |
1392 | * Get the value of a column in the current row as a java.sql.Date object. |
1393 | * |
1394 | * @param columnName is the SQL name of the column |
1395 | * @return the column value; if the value is SQL NULL, the result is null |
1396 | * @exception SQLException thrown on failure. |
1397 | */ |
1398 | public final Date getDate(String columnName) throws SQLException { |
1399 | checkIfClosed("getDate"); |
1400 | return (getDate(findColumnName(columnName))); |
1401 | } |
1402 | |
1403 | /** |
1404 | * Get the value of a column in the current row as a java.sql.Time object. |
1405 | * |
1406 | * @param columnName is the SQL name of the column |
1407 | * @return the column value; if the value is SQL NULL, the result is null |
1408 | * @exception SQLException thrown on failure. |
1409 | */ |
1410 | public final Time getTime(String columnName) throws SQLException { |
1411 | checkIfClosed("getTime"); |
1412 | return (getTime(findColumnName(columnName))); |
1413 | } |
1414 | |
1415 | /** |
1416 | * Get the value of a column in the current row as a java.sql.Timestamp object. |
1417 | * |
1418 | * @param columnName is the SQL name of the column |
1419 | * @return the column value; if the value is SQL NULL, the result is null |
1420 | * @exception SQLException thrown on failure. |
1421 | */ |
1422 | public final Timestamp getTimestamp(String columnName) throws SQLException { |
1423 | checkIfClosed("getTimestamp"); |
1424 | return (getTimestamp(findColumnName(columnName))); |
1425 | } |
1426 | |
1427 | /** |
1428 | * JDBC 2.0 |
1429 | * |
1430 | * <p>Get the value of a column in the current row as a java.io.Reader. |
1431 | * |
1432 | * @exception SQLException Feature not implemented for now. |
1433 | */ |
1434 | public final java.io.Reader getCharacterStream(String columnName) |
1435 | throws SQLException { |
1436 | checkIfClosed("getCharacterStream"); |
1437 | return (getCharacterStream(findColumnName(columnName))); |
1438 | } |
1439 | |
1440 | /** |
1441 | * A column value can be retrieved as a stream of ASCII characters |
1442 | * and then read in chunks from the stream. This method is particularly |
1443 | * suitable for retrieving large LONGVARCHAR values. The JDBC driver will |
1444 | * do any necessary conversion from the database format into ASCII. |
1445 | * |
1446 | * <P><B>Note:</B> All the data in the returned stream must |
1447 | * be read prior to getting the value of any other column. The |
1448 | * next call to a get method implicitly closes the stream. |
1449 | * |
1450 | * @param columnName is the SQL name of the column |
1451 | * @return a Java input stream that delivers the database column value |
1452 | * as a stream of one byte ASCII characters. If the value is SQL NULL |
1453 | * then the result is null. |
1454 | * @exception SQLException thrown on failure. |
1455 | */ |
1456 | public final InputStream getAsciiStream(String columnName) throws SQLException { |
1457 | checkIfClosed("getAsciiStream"); |
1458 | return (getAsciiStream(findColumnName(columnName))); |
1459 | } |
1460 | |
1461 | /** |
1462 | * A column value can be retrieved as a stream of uninterpreted bytes |
1463 | * and then read in chunks from the stream. This method is particularly |
1464 | * suitable for retrieving large LONGVARBINARY values. |
1465 | * |
1466 | * <P><B>Note:</B> All the data in the returned stream must |
1467 | * be read prior to getting the value of any other column. The |
1468 | * next call to a get method implicitly closes the stream. |
1469 | * |
1470 | * @param columnName is the SQL name of the column |
1471 | * @return a Java input stream that delivers the database column value |
1472 | * as a stream of uninterpreted bytes. If the value is SQL NULL |
1473 | * then the result is null. |
1474 | * @exception SQLException thrown on failure. |
1475 | */ |
1476 | public final InputStream getBinaryStream(String columnName) throws SQLException { |
1477 | checkIfClosed("getBinaryStream"); |
1478 | return (getBinaryStream(findColumnName(columnName))); |
1479 | } |
1480 | |
1481 | /** |
1482 | * JDBC 3.0 |
1483 | * |
1484 | * Retrieves the value of the designated column in the current row of this |
1485 | * ResultSet object as a java.net.URL object in the Java programming |
1486 | * language. |
1487 | * |
1488 | * @param columnIndex - |
1489 | * the first column is 1, the second is 2 |
1490 | * @return the column value as a java.net.URL object, if the value is SQL |
1491 | * NULL, the value returned is null in the Java programming language |
1492 | * @exception SQLException |
1493 | * Feature not implemented for now. |
1494 | */ |
1495 | public URL getURL(int columnIndex) throws SQLException { |
1496 | throw Util.notImplemented(); |
1497 | } |
1498 | |
1499 | /** |
1500 | * JDBC 3.0 |
1501 | * |
1502 | * Retrieves the value of the designated column in the current row of this |
1503 | * ResultSet object as a java.net.URL object in the Java programming |
1504 | * language. |
1505 | * |
1506 | * @param columnName - |
1507 | * the SQL name of the column |
1508 | * @return the column value as a java.net.URL object, if the value is SQL |
1509 | * NULL, the value returned is null in the Java programming language |
1510 | * @exception SQLException |
1511 | * Feature not implemented for now. |
1512 | */ |
1513 | public URL getURL(String columnName) throws SQLException { |
1514 | throw Util.notImplemented(); |
1515 | } |
1516 | |
1517 | //===================================================================== |
1518 | // Advanced features: |
1519 | //===================================================================== |
1520 | |
1521 | /** |
1522 | * <p>The first warning reported by calls on this ResultSet is |
1523 | * returned. Subsequent ResultSet warnings will be chained to this |
1524 | * SQLWarning. |
1525 | * |
1526 | * <P>The warning chain is automatically cleared each time a new |
1527 | * row is read. |
1528 | * |
1529 | * <P><B>Note:</B> This warning chain only covers warnings caused |
1530 | * by ResultSet methods. Any warning caused by statement methods |
1531 | * (such as reading OUT parameters) will be chained on the |
1532 | * Statement object. |
1533 | * |
1534 | * @return the first SQLWarning or null |
1535 | * |
1536 | * @exception SQLException Thrown if this ResultSet is closed |
1537 | */ |
1538 | public final SQLWarning getWarnings() throws SQLException { |
1539 | checkIfClosed("getWarnings"); |
1540 | return topWarning; |
1541 | } |
1542 | |
1543 | /** |
1544 | * After this call getWarnings returns null until a new warning is |
1545 | * reported for this ResultSet. |
1546 | * |
1547 | * @exception SQLException Thrown if this ResultSet is closed |
1548 | */ |
1549 | public final void clearWarnings() throws SQLException { |
1550 | checkIfClosed("clearWarnings"); |
1551 | topWarning = null; |
1552 | } |
1553 | |
1554 | /** |
1555 | * Get the name of the SQL cursor used by this ResultSet. |
1556 | * |
1557 | * <P>In SQL, a result table is retrieved through a cursor that is |
1558 | * named. The current row of a result can be updated or deleted |
1559 | * using a positioned update/delete statement that references the |
1560 | * cursor name. |
1561 | * |
1562 | * <P>JDBC supports this SQL feature by providing the name of the |
1563 | * SQL cursor used by a ResultSet. The current row of a ResultSet |
1564 | * is also the current row of this SQL cursor. |
1565 | * |
1566 | * <P><B>Note:</B> If positioned update is not supported a |
1567 | * SQLException is thrown |
1568 | * |
1569 | * @return the ResultSet's SQL cursor name |
1570 | * @exception SQLException thrown on failure. |
1571 | */ |
1572 | public final String getCursorName() throws SQLException { |
1573 | |
1574 | checkIfClosed("getCursorName"); // checking result set closure does not depend |
1575 | // on the underlying connection. Do this |
1576 | // outside of the connection synchronization. |
1577 | |
1578 | return theResults.getCursorName(); |
1579 | } |
1580 | |
1581 | /** |
1582 | * The number, types and properties of a ResultSet's columns |
1583 | * are provided by the getMetaData method. |
1584 | * |
1585 | * @return the description of a ResultSet's columns |
1586 | * @exception SQLException thrown on failure. |
1587 | */ |
1588 | public ResultSetMetaData getMetaData() throws SQLException { |
1589 | |
1590 | checkIfClosed("getMetaData"); // checking result set closure does not depend |
1591 | // on the underlying connection. Do this |
1592 | // outside of the connection synchronization. |
1593 | |
1594 | synchronized (getConnectionSynchronization()) { |
1595 | |
1596 | |
1597 | if (rMetaData == null) { |
1598 | // cache this object and keep returning it |
1599 | rMetaData = newEmbedResultSetMetaData(resultDescription); |
1600 | } |
1601 | return rMetaData; |
1602 | } |
1603 | } |
1604 | |
1605 | /** |
1606 | * JDBC 4.0 |
1607 | * |
1608 | * <p> |
1609 | * Retrieves the holdability for this <code>ResultSet</code> |
1610 | * object. |
1611 | * |
1612 | * @return either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> |
1613 | * or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> |
1614 | * @exception SQLException |
1615 | * if a database error occurs |
1616 | */ |
1617 | public final int getHoldability() throws SQLException { |
1618 | checkIfClosed("getHoldability"); |
1619 | if (theResults.getActivation().getResultSetHoldability()) { |
1620 | return JDBC30Translation.HOLD_CURSORS_OVER_COMMIT; |
1621 | } |
1622 | return JDBC30Translation.CLOSE_CURSORS_AT_COMMIT; |
1623 | } |
1624 | |
1625 | /** |
1626 | * <p>Get the value of a column in the current row as a Java object. |
1627 | * |
1628 | * <p>This method will return the value of the given column as a |
1629 | * Java object. The type of the Java object will be the default |
1630 | * Java Object type corresponding to the column's SQL type, |
1631 | * following the mapping specified in the JDBC spec. |
1632 | * |
1633 | * <p>This method may also be used to read datatabase specific abstract |
1634 | * data types. |
1635 | * |
1636 | * JDBC 2.0 |
1637 | * |
1638 | * New behavior for getObject(). |
1639 | * The behavior of method getObject() is extended to materialize |
1640 | * data of SQL user-defined types. When the column @columnIndex is |
1641 | * a structured or distinct value, the behavior of this method is as |
1642 | * if it were a call to: getObject(columnIndex, |
1643 | * this.getStatement().getConnection().getTypeMap()). |
1644 | * |
1645 | * @param columnIndex the first column is 1, the second is 2, ... |
1646 | * @return A java.lang.Object holding the column value. |
1647 | * @exception SQLException thrown on failure. |
1648 | */ |
1649 | public final Object getObject(int columnIndex) throws SQLException { |
1650 | checkIfClosed("getObject"); |
1651 | |
1652 | // need special handling for some types. |
1653 | int colType = getColumnType(columnIndex); |
1654 | switch (colType) { |
1655 | case Types.CHAR: |
1656 | case Types.VARCHAR: |
1657 | case Types.LONGVARCHAR: |
1658 | // handles maxfield size correctly |
1659 | return getString(columnIndex); |
1660 | |
1661 | case Types.CLOB: |
1662 | return getClob(columnIndex); |
1663 | |
1664 | case Types.BINARY: |
1665 | case Types.VARBINARY: |
1666 | case Types.LONGVARBINARY: |
1667 | // handles maxfield size correctly |
1668 | return getBytes(columnIndex); |
1669 | |
1670 | case Types.BLOB: |
1671 | return getBlob(columnIndex); |
1672 | |
1673 | default: |
1674 | break; |
1675 | } |
1676 | |
1677 | try { |
1678 | |
1679 | DataValueDescriptor dvd = getColumn(columnIndex); |
1680 | if (wasNull = dvd.isNull()) |
1681 | return null; |
1682 | |
1683 | return dvd.getObject(); |
1684 | |
1685 | } catch (StandardException t) { |
1686 | throw noStateChangeException(t); |
1687 | } |
1688 | } |
1689 | |
1690 | /** |
1691 | * <p>Get the value of a column in the current row as a Java object. |
1692 | * |
1693 | * <p>This method will return the value of the given column as a |
1694 | * Java object. The type of the Java object will be the default |
1695 | * Java Object type corresponding to the column's SQL type, |
1696 | * following the mapping specified in the JDBC spec. |
1697 | * |
1698 | * <p>This method may also be used to read datatabase specific abstract |
1699 | * data types. |
1700 | * |
1701 | * JDBC 2.0 |
1702 | * |
1703 | * New behavior for getObject(). |
1704 | * The behavior of method getObject() is extended to materialize |
1705 | * data of SQL user-defined types. When the column @columnName is |
1706 | * a structured or distinct value, the behavior of this method is as |
1707 | * if it were a call to: getObject(columnName, |
1708 | * this.getStatement().getConnection().getTypeMap()). |
1709 | * |
1710 | * @param columnName is the SQL name of the column |
1711 | * @return A java.lang.Object holding the column value. |
1712 | * @exception SQLException thrown on failure. |
1713 | */ |
1714 | public final Object getObject(String columnName) throws SQLException { |
1715 | checkIfClosed("getObject"); |
1716 | return (getObject(findColumnName(columnName))); |
1717 | } |
1718 | |
1719 | |
1720 | //---------------------------------------------------------------- |
1721 | |
1722 | /** |
1723 | * Map a Resultset column name to a ResultSet column index. |
1724 | * |
1725 | * @param columnName the name of the column |
1726 | * @return the column index |
1727 | * @exception SQLException thrown on failure. |
1728 | */ |
1729 | public final int findColumn(String columnName) throws SQLException { |
1730 | checkIfClosed("findColumn"); |
1731 | return findColumnName(columnName); |
1732 | } |
1733 | |
1734 | ///////////////////////////////////////////////////////////////////////// |
1735 | // |
1736 | // JDBC 2.0 - New public methods |
1737 | // |
1738 | ///////////////////////////////////////////////////////////////////////// |
1739 | |
1740 | |
1741 | //--------------------------------------------------------------------- |
1742 | // Getter's and Setter's |
1743 | //--------------------------------------------------------------------- |
1744 | |
1745 | /** |
1746 | * JDBC 2.0 |
1747 | * |
1748 | * Return the Statement that produced the ResultSet. |
1749 | * |
1750 | * @return the Statment that produced the result set, or null if the result |
1751 | * was produced some other way. |
1752 | * @exception SQLException if a database error occurs or the |
1753 | * result set is closed |
1754 | */ |
1755 | public final Statement getStatement() throws SQLException |
1756 | { |
1757 | checkIfClosed("getStatement"); |
1758 | return applicationStmt; |
1759 | } |
1760 | |
1761 | /** |
1762 | * Set the application Statement object that created this ResultSet. |
1763 | * Used when the Statement objects returned to the application |
1764 | * are wrapped for XA. |
1765 | */ |
1766 | public final void setApplicationStatement(Statement applicationStmt) |
1767 | { |
1768 | this.applicationStmt = applicationStmt; |
1769 | } |
1770 | |
1771 | //--------------------------------------------------------------------- |
1772 | // Traversal/Positioning |
1773 | //--------------------------------------------------------------------- |
1774 | |
1775 | /** |
1776 | * JDBC 2.0 |
1777 | * |
1778 | * <p> |
1779 | * Determine if the cursor is before the first row in the result set. |
1780 | * |
1781 | * @return true if before the first row, false otherwise. Returns false when |
1782 | * the result set contains no rows. |
1783 | * @exception SQLException |
1784 | * Thrown on error. |
1785 | */ |
1786 | public boolean isBeforeFirst() throws SQLException { |
1787 | return checkRowPosition(ResultSet.ISBEFOREFIRST, "isBeforeFirst"); |
1788 | } |
1789 | |
1790 | /** |
1791 | * JDBC 2.0 |
1792 | * |
1793 | * <p> |
1794 | * Determine if the cursor is after the last row in the result set. |
1795 | * |
1796 | * @return true if after the last row, false otherwise. Returns false when |
1797 | * the result set contains no rows. |
1798 | * @exception SQLException |
1799 | * Thrown on error. |
1800 | */ |
1801 | public boolean isAfterLast() throws SQLException { |
1802 | return checkRowPosition(ResultSet.ISAFTERLAST, "isAfterLast"); |
1803 | } |
1804 | |
1805 | /** |
1806 | * JDBC 2.0 |
1807 | * |
1808 | * <p> |
1809 | * Determine if the cursor is on the first row of the result set. |
1810 | * |
1811 | * @return true if on the first row, false otherwise. |
1812 | * @exception SQLException |
1813 | * Thrown on error. |
1814 | */ |
1815 | public boolean isFirst() throws SQLException { |
1816 | return checkRowPosition(ResultSet.ISFIRST, "isFirst"); |
1817 | } |
1818 | |
1819 | /** |
1820 | * JDBC 2.0 |
1821 | * |
1822 | * <p> |
1823 | * Determine if the cursor is on the last row of the result set. Note: |
1824 | * Calling isLast() may be expensive since the JDBC driver might need to |
1825 | * fetch ahead one row in order to determine whether the current row is the |
1826 | * last row in the result set. |
1827 | * |
1828 | * @return true if on the last row, false otherwise. |
1829 | * @exception SQLException |
1830 | * Thrown on error. |
1831 | */ |
1832 | public boolean isLast() throws SQLException { |
1833 | return checkRowPosition(ResultSet.ISLAST, "isLast"); |
1834 | } |
1835 | |
1836 | /** |
1837 | * JDBC 2.0 |
1838 | * |
1839 | * <p> |
1840 | * Moves to the front of the result set, just before the first row. Has no |
1841 | * effect if the result set contains no rows. |
1842 | * |
1843 | * @exception SQLException |
1844 | * if a database-access error occurs, or result set type is |
1845 | * TYPE_FORWARD_ONLY |
1846 | */ |
1847 | public void beforeFirst() throws SQLException { |
1848 | // beforeFirst is only allowed on scroll cursors |
1849 | checkScrollCursor("beforeFirst()"); |
1850 | movePosition(BEFOREFIRST, "beforeFirst"); |
1851 | } |
1852 | |
1853 | /** |
1854 | * JDBC 2.0 |
1855 | * |
1856 | * <p> |
1857 | * Moves to the end of the result set, just after the last row. Has no |
1858 | * effect if the result set contains no rows. |
1859 | * |
1860 | * @exception SQLException |
1861 | * if a database-access error occurs, or result set type is |
1862 | * TYPE_FORWARD_ONLY. |
1863 | */ |
1864 | public void afterLast() throws SQLException { |
1865 | // afterLast is only allowed on scroll cursors |
1866 | checkScrollCursor("afterLast()"); |
1867 | movePosition(AFTERLAST, "afterLast"); |
1868 | } |
1869 | |
1870 | /** |
1871 | * JDBC 2.0 |
1872 | * |
1873 | * <p> |
1874 | * Moves to the first row in the result set. |
1875 | * |
1876 | * @return true if on a valid row, false if no rows in the result set. |
1877 | * @exception SQLException |
1878 | * if a database-access error occurs, or result set type is |
1879 | * TYPE_FORWARD_ONLY. |
1880 | */ |
1881 | public boolean first() throws SQLException { |
1882 | // first is only allowed on scroll cursors |
1883 | checkScrollCursor("first()"); |
1884 | return movePosition(FIRST, "first"); |
1885 | } |
1886 | |
1887 | /** |
1888 | * JDBC 2.0 |
1889 | * |
1890 | * <p> |
1891 | * Moves to the last row in the result set. |
1892 | * |
1893 | * @return true if on a valid row, false if no rows in the result set. |
1894 | * @exception SQLException |
1895 | * if a database-access error occurs, or result set type is |
1896 | * TYPE_FORWARD_ONLY. |
1897 | */ |
1898 | public boolean last() throws SQLException { |
1899 | // last is only allowed on scroll cursors |
1900 | checkScrollCursor("last()"); |
1901 | return movePosition(LAST, "last"); |
1902 | } |
1903 | |
1904 | /** |
1905 | * JDBC 2.0 |
1906 | * |
1907 | * <p> |
1908 | * Determine the current row number. The first row is number 1, the second |
1909 | * number 2, etc. |
1910 | * |
1911 | * @return the current row number, else return 0 if there is no current row |
1912 | * @exception SQLException |
1913 | * if a database-access error occurs. |
1914 | */ |
1915 | public int getRow() throws SQLException { |
1916 | // getRow() is only allowed on scroll cursors |
1917 | checkScrollCursor("getRow()"); |
1918 | |
1919 | /* |
1920 | * * We probably needn't bother getting the text of * the underlying |
1921 | * statement but it is better to be * consistent and we aren't |
1922 | * particularly worried * about performance of getRow(). |
1923 | */ |
1924 | return theResults.getRowNumber(); |
1925 | } |
1926 | |
1927 | /** |
1928 | * JDBC 2.0 |
1929 | * |
1930 | * <p> |
1931 | * Move to an absolute row number in the result set. |
1932 | * |
1933 | * <p> |
1934 | * If row is positive, moves to an absolute row with respect to the |
1935 | * beginning of the result set. The first row is row 1, the second is row 2, |
1936 | * etc. |
1937 | * |
1938 | * <p> |
1939 | * If row is negative, moves to an absolute row position with respect to the |
1940 | * end of result set. For example, calling absolute(-1) positions the cursor |
1941 | * on the last row, absolute(-2) indicates the next-to-last row, etc. |
1942 | * |
1943 | * <p> |
1944 | * An attempt to position the cursor beyond the first/last row in the result |
1945 | * set, leaves the cursor before/after the first/last row, respectively. |
1946 | * |
1947 | * <p> |
1948 | * Note: Calling absolute(1) is the same as calling first(). Calling |
1949 | * absolute(-1) is the same as calling last(). |
1950 | * |
1951 | * @return true if on the result set, false if off. |
1952 | * @exception SQLException |
1953 | * if a database-access error occurs, or row is 0, or result |
1954 | * set type is TYPE_FORWARD_ONLY. |
1955 | */ |
1956 | public boolean absolute(int row) throws SQLException { |
1957 | // absolute is only allowed on scroll cursors |
1958 | checkScrollCursor("absolute()"); |
1959 | return movePosition(ABSOLUTE, row, "absolute"); |
1960 | } |
1961 | |
1962 | /** |
1963 | * JDBC 2.0 |
1964 | * |
1965 | * <p> |
1966 | * Moves a relative number of rows, either positive or negative. Attempting |
1967 | * to move beyond the first/last row in the result set positions the cursor |
1968 | * before/after the the first/last row. Calling relative(0) is valid, but |
1969 | * does not change the cursor position. |
1970 | * |
1971 | * <p> |
1972 | * Note: Calling relative(1) is different than calling next() since is makes |
1973 | * sense to call next() when there is no current row, for example, when the |
1974 | * cursor is positioned before the first row or after the last row of the |
1975 | * result set. |
1976 | * |
1977 | * @return true if on a row, false otherwise. |
1978 | * @exception SQLException |
1979 | * if a database-access error occurs, or there is no current |
1980 | * row, or result set type is TYPE_FORWARD_ONLY. |
1981 | */ |
1982 | public boolean relative(int row) throws SQLException { |
1983 | // absolute is only allowed on scroll cursors |
1984 | checkScrollCursor("relative()"); |
1985 | return movePosition(RELATIVE, row, "relative"); |
1986 | } |
1987 | |
1988 | /** |
1989 | * JDBC 2.0 |
1990 | * |
1991 | * <p> |
1992 | * Moves to the previous row in the result set. |
1993 | * |
1994 | * <p> |
1995 | * Note: previous() is not the same as relative(-1) since it makes sense to |
1996 | * call previous() when there is no current row. |
1997 | * |
1998 | * @return true if on a valid row, false if off the result set. |
1999 | * @exception SQLException |
2000 | * if a database-access error occurs, or result set type is |
2001 | * TYPE_FORWAR_DONLY. |
2002 | */ |
2003 | public boolean previous() throws SQLException { |
2004 | // previous is only allowed on scroll cursors |
2005 | checkScrollCursor("previous()"); |
2006 | return movePosition(PREVIOUS, "previous"); |
2007 | } |
2008 | |
2009 | //--------------------------------------------------------------------- |
2010 | // Properties |
2011 | //--------------------------------------------------------------------- |
2012 | |
2013 | /** |
2014 | * JDBC 2.0 |
2015 | * |
2016 | * Give a hint as to the direction in which the rows in this result set will |
2017 | * be processed. The initial value is determined by the statement that |
2018 | * produced the result set. The fetch direction may be changed at any time. |
2019 | * |
2020 | * @exception SQLException |
2021 | * if a database-access error occurs, or the result set type |
2022 | * is TYPE_FORWARD_ONLY and direction is not FETCH_FORWARD. |
2023 | */ |
2024 | public void setFetchDirection(int direction) throws SQLException { |
2025 | checkScrollCursor("setFetchDirection()"); |
2026 | /* |
2027 | * FetchDirection is meaningless to us. We just save it off and return |
2028 | * the current value if asked. |
2029 | */ |
2030 | fetchDirection = direction; |
2031 | } |
2032 | |
2033 | /** |
2034 | * JDBC 2.0 |
2035 | * |
2036 | * Return the fetch direction for this result set. |
2037 | * |
2038 | * @exception SQLException |
2039 | * if a database-access error occurs |
2040 | */ |
2041 | public int getFetchDirection() throws SQLException { |
2042 | checkIfClosed("getFetchDirection"); |
2043 | if (fetchDirection == 0) { |
2044 | // value is not set at the result set level |
2045 | // get it from the statement level |
2046 | return stmt.getFetchDirection(); |
2047 | } else |
2048 | return fetchDirection; |
2049 | } |
2050 | |
2051 | /** |
2052 | * JDBC 2.0 |
2053 | * |
2054 | * Give the JDBC driver a hint as to the number of rows that should be |
2055 | * fetched from the database when more rows are needed for this result set. |
2056 | * If the fetch size specified is zero, then the JDBC driver ignores the |
2057 | * value, and is free to make its own best guess as to what the fetch size |
2058 | * should be. The default value is set by the statement that creates the |
2059 | * result set. The fetch size may be changed at any time. |
2060 | * |
2061 | * @param rows |
2062 | * the number of rows to fetch |
2063 | * @exception SQLException |
2064 | * if a database-access error occurs, or the condition 0 <= |
2065 | * rows <= this.getMaxRows() is not satisfied. |
2066 | */ |
2067 | public void setFetchSize(int rows) throws SQLException { |
2068 | checkIfClosed("setFetchSize"); |
2069 | if (rows < 0 || (stmt.getMaxRows() != 0 && rows > stmt.getMaxRows())) { |
2070 | throw Util.generateCsSQLException(SQLState.INVALID_FETCH_SIZE, |
2071 | new Integer(rows)); |
2072 | } else if (rows > 0) // if it is zero ignore the call |
2073 | { |
2074 | fetchSize = rows; |
2075 | } |
2076 | } |
2077 | |
2078 | /** |
2079 | * JDBC 2.0 |
2080 | * |
2081 | * Return the fetch size for this result set. |
2082 | * |
2083 | * @exception SQLException |
2084 | * if a database-access error occurs |
2085 | */ |
2086 | public int getFetchSize() throws SQLException { |
2087 | checkIfClosed("getFetchSize"); |
2088 | if (fetchSize == 0) { |
2089 | // value is not set at the result set level |
2090 | // get the default value from the statement |
2091 | return stmt.getFetchSize(); |
2092 | } else |
2093 | return fetchSize; |
2094 | } |
2095 | |
2096 | /** |
2097 | * JDBC 2.0 |
2098 | * |
2099 | * Return the type of this result set. The type is determined based on the |
2100 | * statement that created the result set. |
2101 | * |
2102 | * @return TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or |
2103 | * TYPE_SCROLL_SENSITIVE |
2104 | * @exception SQLException |
2105 | * if a database-access error occurs |
2106 | */ |
2107 | public int getType() throws SQLException { |
2108 | checkIfClosed("getType"); |
2109 | return stmt.getResultSetType(); |
2110 | } |
2111 | |
2112 | /** |
2113 | * JDBC 2.0 |
2114 | * |
2115 | * Return the concurrency of this result set. The concurrency is determined |
2116 | * as follows If Statement object has CONCUR_READ_ONLY concurrency, then |
2117 | * ResultSet object will also have the CONCUR_READ_ONLY concurrency. But if |
2118 | * Statement object has CONCUR_UPDATABLE concurrency, then the concurrency |
2119 | * of ResultSet object depends on whether the underlying language resultset |
2120 | * is updatable or not. If the language resultset is updatable, then JDBC |
2121 | * ResultSet object will also have the CONCUR_UPDATABLE concurrency. If |
2122 | * lanugage resultset is not updatable, then JDBC ResultSet object |
2123 | * concurrency will be set to CONCUR_READ_ONLY. |
2124 | * |
2125 | * @return the concurrency type, CONCUR_READ_ONLY, etc. |
2126 | * @exception SQLException |
2127 | * if a database-access error occurs |
2128 | */ |
2129 | public int getConcurrency() throws SQLException { |
2130 | checkIfClosed("getConcurrency"); |
2131 | return concurrencyOfThisResultSet; |
2132 | } |
2133 | |
2134 | //--------------------------------------------------------------------- |
2135 | // Updates |
2136 | //--------------------------------------------------------------------- |
2137 | |
2138 | /** |
2139 | * JDBC 2.0 |
2140 | * |
2141 | * Determine if the current row has been updated. The value returned depends |
2142 | * on whether or not the result set can detect updates. |
2143 | * |
2144 | * @return true if the row has been visibly updated by the owner or another, |
2145 | * and updates are detected |
2146 | * @exception SQLException |
2147 | * if a database-access error occurs |
2148 | * |
2149 | * @see EmbedDatabaseMetaData#updatesAreDetected |
2150 | */ |
2151 | public boolean rowUpdated() throws SQLException { |
2152 | checkIfClosed("rowUpdated"); |
2153 | checkNotOnInsertRow(); |
2154 | checkOnRow(); |
2155 | |
2156 | boolean rvalue = false; |
2157 | |
2158 | try { |
2159 | if (isForUpdate() && |
2160 | getType() == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE) { |
2161 | rvalue = ((ScrollInsensitiveResultSet)theResults).isUpdated(); |
2162 | } |
2163 | } catch (Throwable t) { |
2164 | handleException(t); |
2165 | } |
2166 | return rvalue; |
2167 | } |
2168 | |
2169 | /** |
2170 | * JDBC 2.0 |
2171 | * |
2172 | * Determine if the current row has been inserted. The value returned |
2173 | * depends on whether or not the result set can detect visible inserts. |
2174 | * |
2175 | * @return true if inserted and inserts are detected |
2176 | * @exception SQLException |
2177 | * if a database-access error occurs |
2178 | * |
2179 | * @see EmbedDatabaseMetaData#insertsAreDetected |
2180 | */ |
2181 | public boolean rowInserted() throws SQLException { |
2182 | checkIfClosed("rowInserted"); |
2183 | checkNotOnInsertRow(); |
2184 | checkOnRow(); |
2185 | |
2186 | return false; |
2187 | } |
2188 | |
2189 | /** |
2190 | * JDBC 2.0 |
2191 | * |
2192 | * Determine if this row has been deleted. A deleted row may leave a visible |
2193 | * "hole" in a result set. This method can be used to detect holes in a |
2194 | * result set. The value returned depends on whether or not the result set |
2195 | * can detect deletions. |
2196 | * |
2197 | * @return true if deleted and deletes are detected |
2198 | * @exception SQLException |
2199 | * if a database-access error occurs |
2200 | * |
2201 | * @see EmbedDatabaseMetaData#deletesAreDetected |
2202 | */ |
2203 | public boolean rowDeleted() throws SQLException { |
2204 | checkIfClosed("rowUpdated"); |
2205 | checkNotOnInsertRow(); |
2206 | checkOnRow(); |
2207 | |
2208 | boolean rvalue = false; |
2209 | |
2210 | try { |
2211 | if (isForUpdate() && |
2212 | getType() == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE) { |
2213 | rvalue = ((ScrollInsensitiveResultSet)theResults).isDeleted(); |
2214 | } |
2215 | } catch (Throwable t) { |
2216 | handleException(t); |
2217 | } |
2218 | return rvalue; |
2219 | } |
2220 | |
2221 | //do following few checks before accepting updateXXX resultset api |
2222 | protected void checksBeforeUpdateXXX(String methodName, int columnIndex) throws SQLException { |
2223 | checksBeforeUpdateOrDelete(methodName, columnIndex); |
2224 | |
2225 | //1)Make sure for updateXXX methods, the column position is not out of range |
2226 | ResultDescription rd = theResults.getResultDescription(); |
2227 | if (columnIndex < 1 || columnIndex > rd.getColumnCount()) |
2228 | throw Util.generateCsSQLException(SQLState.LANG_INVALID_COLUMN_POSITION, |
2229 | new Integer(columnIndex), String.valueOf(rd.getColumnCount())); |
2230 | |
2231 | //2)Make sure the column corresponds to a column in the base table and it is not a derived column |
2232 | if (rd.getColumnDescriptor(columnIndex).getSourceTableName() == null) |
2233 | throw Util.generateCsSQLException(SQLState.COLUMN_NOT_FROM_BASE_TABLE, |
2234 | methodName); |
2235 | |
2236 | //3)If column not updatable then throw an exception |
2237 | if (!getMetaData().isWritable(columnIndex)) |
2238 | throw Util.generateCsSQLException(SQLState.LANG_COLUMN_NOT_UPDATABLE_IN_CURSOR, |
2239 | theResults.getResultDescription().getColumnDescriptor(columnIndex).getName(), |
2240 | getCursorName()); |
2241 | } |
2242 | |
2243 | //do following few checks before accepting updateRow or deleteRow |
2244 | //1)Make sure JDBC ResultSet is not closed |
2245 | //2)Make sure this is an updatable ResultSet |
2246 | //3)Make sure JDBC ResultSet is positioned on a row |
2247 | //4)Make sure underneath language resultset is not closed |
2248 | protected void checksBeforeUpdateOrDelete(String methodName, int columnIndex) throws SQLException { |
2249 | |
2250 | //1)Make sure JDBC ResultSet is not closed |
2251 | checkIfClosed(methodName); |
2252 | |
2253 | //2)Make sure this is an updatable ResultSet |
2254 | checkUpdatableCursor(methodName); |
2255 | |
2256 | //3)Make sure JDBC ResultSet is positioned on a row |
2257 | if (!isOnInsertRow) checkOnRow(); // make sure there's a current row |
2258 | //in case of autocommit on, if there was an exception which caused runtime rollback in this transaction prior to this call, |
2259 | //the rollback code will mark the language resultset closed (it doesn't mark the JDBC ResultSet closed). |
2260 | //That is why alongwith the earlier checkIfClosed call in this method, there is a check for language resultset close as well. |
2261 | |
2262 | //4)Make sure underneath language resultset is not closed |
2263 | if (theResults.isClosed()) |
2264 | throw Util.generateCsSQLException(SQLState.LANG_RESULT_SET_NOT_OPEN, methodName); |
2265 | } |
2266 | |
2267 | //mark the column as updated and return DataValueDescriptor for it. It will be used by updateXXX methods to put new values |
2268 | protected DataValueDescriptor getDVDforColumnToBeUpdated(int columnIndex, String updateMethodName) throws StandardException, SQLException { |
2269 | checksBeforeUpdateXXX(updateMethodName, columnIndex); |
2270 | columnGotUpdated[columnIndex-1] = true; |
2271 | currentRowHasBeenUpdated = true; |
2272 | |
2273 | return updateRow.getColumn(columnIndex); |
2274 | } |
2275 | |
2276 | /* do following few checks before accepting insertRow |
2277 | * 1) Make sure JDBC ResultSet is not closed |
2278 | * 2) Make sure this is an updatable ResultSet |
2279 | * 3) Make sure JDBC ResultSet is positioned on insertRow |
2280 | * 4) Make sure underneath language resultset is not closed |
2281 | */ |
2282 | protected void checksBeforeInsert() throws SQLException { |
2283 | // 1)Make sure JDBC ResultSet is not closed |
2284 | checkIfClosed("insertRow"); |
2285 | |
2286 | // 2)Make sure this is an updatable ResultSet |
2287 | // if not updatable resultset, then throw exception |
2288 | checkUpdatableCursor("insertRow"); |
2289 | |
2290 | // 3)Make sure JDBC ResultSet is positioned on insertRow |
2291 | if (!isOnInsertRow) { |
2292 | throw newSQLException(SQLState.CURSOR_NOT_POSITIONED_ON_INSERT_ROW); |
2293 | } |
2294 | |
2295 | // 4)Make sure underneath language resultset is not closed |
2296 | if (theResults.isClosed()) { |
2297 | throw Util.generateCsSQLException(SQLState.LANG_RESULT_SET_NOT_OPEN, "insertRow"); |
2298 | } |
2299 | } |
2300 | |
2301 | |
2302 | /** |
2303 | * JDBC 2.0 |
2304 | * |
2305 | * Give a nullable column a null value. |
2306 | * |
2307 | * The updateXXX() methods are used to update column values in the current |
2308 | * row, or the insert row. The updateXXX() methods do not update the |
2309 | * underlying database, instead the updateRow() or insertRow() methods are |
2310 | * called to update the database. |
2311 | * |
2312 | * @param columnIndex |
2313 | * the first column is 1, the second is 2, ... |
2314 | * @exception SQLException |
2315 | * if a database-access error occurs |
2316 | */ |
2317 | public void updateNull(int columnIndex) throws SQLException { |
2318 | try { |
2319 | getDVDforColumnToBeUpdated(columnIndex, "updateNull").setToNull(); |
2320 | } catch (StandardException t) { |
2321 | throw noStateChangeException(t); |
2322 | } |
2323 | } |
2324 | |
2325 | /** |
2326 | * JDBC 2.0 |
2327 | * |
2328 | * Update a column with a boolean value. |
2329 | * |
2330 | * The updateXXX() methods are used to update column values in the current |
2331 | * row, or the insert row. The updateXXX() methods do not update the |
2332 | * underlying database, instead the updateRow() or insertRow() methods are |
2333 | * called to update the database. |
2334 | * |
2335 | * @param columnIndex |
2336 | * the first column is 1, the second is 2, ... |
2337 | * @param x |
2338 | * the new column value |
2339 | * @exception SQLException |
2340 | * if a database-access error occurs |
2341 | */ |
2342 | public void updateBoolean(int columnIndex, boolean x) throws SQLException { |
2343 | try { |
2344 | getDVDforColumnToBeUpdated(columnIndex, "updateBoolean").setValue(x); |
2345 | } catch (StandardException t) { |
2346 | throw noStateChangeException(t); |
2347 | } |
2348 | } |
2349 | |
2350 | /** |
2351 | * JDBC 2.0 |
2352 | * |
2353 | * Update a column with a byte value. |
2354 | * |
2355 | * The updateXXX() methods are used to update column values in the current |
2356 | * row, or the insert row. The updateXXX() methods do not update the |
2357 | * underlying database, instead the updateRow() or insertRow() methods are |
2358 | * called to update the database. |
2359 | * |
2360 | * @param columnIndex |
2361 | * the first column is 1, the second is 2, ... |
2362 | * @param x |
2363 | * the new column value |
2364 | * @exception SQLException |
2365 | * if a database-access error occurs |
2366 | */ |
2367 | public void updateByte(int columnIndex, byte x) throws SQLException { |
2368 | try { |
2369 | getDVDforColumnToBeUpdated(columnIndex, "updateByte").setValue(x); |
2370 | } catch (StandardException t) { |
2371 | throw noStateChangeException(t); |
2372 | } |
2373 | } |
2374 | |
2375 | /** |
2376 | * JDBC 2.0 |
2377 | * |
2378 | * Update a column with a short value. |
2379 | * |
2380 | * The updateXXX() methods are used to update column values in the current |
2381 | * row, or the insert row. The updateXXX() methods do not update the |
2382 | * underlying database, instead the updateRow() or insertRow() methods are |
2383 | * called to update the database. |
2384 | * |
2385 | * @param columnIndex |
2386 | * the first column is 1, the second is 2, ... |
2387 | * @param x |
2388 | * the new column value |
2389 | * @exception SQLException |
2390 | * if a database-access error occurs |
2391 | */ |
2392 | public void updateShort(int columnIndex, short x) throws SQLException { |
2393 | try { |
2394 | getDVDforColumnToBeUpdated(columnIndex, "updateShort").setValue(x); |
2395 | } catch (StandardException t) { |
2396 | throw noStateChangeException(t); |
2397 | } |
2398 | } |
2399 | |
2400 | /** |
2401 | * JDBC 2.0 |
2402 | * |
2403 | * Update a column with an integer value. |
2404 | * |
2405 | * The updateXXX() methods are used to update column values in the current |
2406 | * row, or the insert row. The updateXXX() methods do not update the |
2407 | * underlying database, instead the updateRow() or insertRow() methods are |
2408 | * called to update the database. |
2409 | * |
2410 | * @param columnIndex |
2411 | * the first column is 1, the second is 2, ... |
2412 | * @param x |
2413 | * the new column value |
2414 | * @exception SQLException |
2415 | * if a database-access error occurs |
2416 | */ |
2417 | public void updateInt(int columnIndex, int x) throws SQLException { |
2418 | try { |
2419 | getDVDforColumnToBeUpdated(columnIndex, "updateInt").setValue(x); |
2420 | } catch (StandardException t) { |
2421 | throw noStateChangeException(t); |
2422 | } |
2423 | } |
2424 | |
2425 | /** |
2426 | * JDBC 2.0 |
2427 | * |
2428 | * Update a column with a long value. |
2429 | * |
2430 | * The updateXXX() methods are used to update column values in the current |
2431 | * row, or the insert row. The updateXXX() methods do not update the |
2432 | * underlying database, instead the updateRow() or insertRow() methods are |
2433 | * called to update the database. |
2434 | * |
2435 | * @param columnIndex |
2436 | * the first column is 1, the second is 2, ... |
2437 | * @param x |
2438 | * the new column value |
2439 | * @exception SQLException |
2440 | * if a database-access error occurs |
2441 | */ |
2442 | public void updateLong(int columnIndex, long x) throws SQLException { |
2443 | try { |
2444 | getDVDforColumnToBeUpdated(columnIndex, "updateLong").setValue(x); |
2445 | } catch (StandardException t) { |
2446 | throw noStateChangeException(t); |
2447 | } |
2448 | } |
2449 | |
2450 | /** |
2451 | * JDBC 2.0 |
2452 | * |
2453 | * Update a column with a float value. |
2454 | * |
2455 | * The updateXXX() methods are used to update column values in the current |
2456 | * row, or the insert row. The updateXXX() methods do not update the |
2457 | * underlying database, instead the updateRow() or insertRow() methods are |
2458 | * called to update the database. |
2459 | * |
2460 | * @param columnIndex |
2461 | * the first column is 1, the second is 2, ... |
2462 | * @param x |
2463 | * the new column value |
2464 | * @exception SQLException |
2465 | * if a database-access error occurs |
2466 | */ |
2467 | public void updateFloat(int columnIndex, float x) throws SQLException { |
2468 | try { |
2469 | getDVDforColumnToBeUpdated(columnIndex, "updateFloat").setValue(x); |
2470 | } catch (StandardException t) { |
2471 | throw noStateChangeException(t); |
2472 | } |
2473 | } |
2474 | |
2475 | /** |
2476 | * JDBC 2.0 |
2477 | * |
2478 | * Update a column with a Double value. |
2479 | * |
2480 | * The updateXXX() methods are used to update column values in the current |
2481 | * row, or the insert row. The updateXXX() methods do not update the |
2482 | * underlying database, instead the updateRow() or insertRow() methods are |
2483 | * called to update the database. |
2484 | * |
2485 | * @param columnIndex |
2486 | * the first column is 1, the second is 2, ... |
2487 | * @param x |
2488 | * the new column value |
2489 | * @exception SQLException |
2490 | * if a database-access error occurs |
2491 | */ |
2492 | public void updateDouble(int columnIndex, double x) throws SQLException { |
2493 | try { |
2494 | getDVDforColumnToBeUpdated(columnIndex, "updateDouble").setValue(x); |
2495 | } catch (StandardException t) { |
2496 | throw noStateChangeException(t); |
2497 | } |
2498 | } |
2499 | |
2500 | /** |
2501 | * JDBC 2.0 |
2502 | * |
2503 | * Update a column with a String value. |
2504 | * |
2505 | * The updateXXX() methods are used to update column values in the current |
2506 | * row, or the insert row. The updateXXX() methods do not update the |
2507 | * underlying database, instead the updateRow() or insertRow() methods are |
2508 | * called to update the database. |
2509 | * |
2510 | * @param columnIndex |
2511 | * the first column is 1, the second is 2, ... |
2512 | * @param x |
2513 | * the new column value |
2514 | * @exception SQLException |
2515 | * if a database-access error occurs |
2516 | */ |
2517 | public void updateString(int columnIndex, String x) throws SQLException { |
2518 | try { |
2519 | getDVDforColumnToBeUpdated(columnIndex, "updateString").setValue(x); |
2520 | } catch (StandardException t) { |
2521 | throw noStateChangeException(t); |
2522 | } |
2523 | } |
2524 | |
2525 | /** |
2526 | * JDBC 2.0 |
2527 | * |
2528 | * Update a column with a byte array value. |
2529 | * |
2530 | * The updateXXX() methods are used to update column values in the current |
2531 | * row, or the insert row. The updateXXX() methods do not update the |
2532 | * underlying database, instead the updateRow() or insertRow() methods are |
2533 | * called to update the database. |
2534 | * |
2535 | * @param columnIndex |
2536 | * the first column is 1, the second is 2, ... |
2537 | * @param x |
2538 | * the new column value |
2539 | * @exception SQLException |
2540 | * if a database-access error occurs |
2541 | */ |
2542 | public void updateBytes(int columnIndex, byte x[]) throws SQLException { |
2543 | try { |
2544 | getDVDforColumnToBeUpdated(columnIndex, "updateBytes").setValue(x); |
2545 | } catch (StandardException t) { |
2546 | throw noStateChangeException(t); |
2547 | } |
2548 | } |
2549 | |
2550 | /** |
2551 | * JDBC 2.0 |
2552 | * |
2553 | * Update a column with a Date value. |
2554 | * |
2555 | * The updateXXX() methods are used to update column values in the current |
2556 | * row, or the insert row. The updateXXX() methods do not update the |
2557 | * underlying database, instead the updateRow() or insertRow() methods are |
2558 | * called to update the database. |
2559 | * |
2560 | * @param columnIndex |
2561 | * the first column is 1, the second is 2, ... |
2562 | * @param x |
2563 | * the new column value |
2564 | * @exception SQLException |
2565 | * if a database-access error occurs |
2566 | */ |
2567 | public void updateDate(int columnIndex, java.sql.Date x) |
2568 | throws SQLException { |
2569 | try { |
2570 | getDVDforColumnToBeUpdated(columnIndex, "updateDate").setValue(x); |
2571 | } catch (StandardException t) { |
2572 | throw noStateChangeException(t); |
2573 | } |
2574 | } |
2575 | |
2576 | /** |
2577 | * JDBC 2.0 |
2578 | * |
2579 | * Update a column with a Time value. |
2580 | * |
2581 | * The updateXXX() methods are used to update column values in the current |
2582 | * row, or the insert row. The updateXXX() methods do not update the |
2583 | * underlying database, instead the updateRow() or insertRow() methods are |
2584 | * called to update the database. |
2585 | * |
2586 | * @param columnIndex |
2587 | * the first column is 1, the second is 2, ... |
2588 | * @param x |
2589 | * the new column value |
2590 | * @exception SQLException |
2591 | * if a database-access error occurs |
2592 | */ |
2593 | public void updateTime(int columnIndex, java.sql.Time x) |
2594 | throws SQLException { |
2595 | try { |
2596 | getDVDforColumnToBeUpdated(columnIndex, "updateTime").setValue(x); |
2597 | } catch (StandardException t) { |
2598 | throw noStateChangeException(t); |
2599 | } |
2600 | } |
2601 | |
2602 | /** |
2603 | * JDBC 2.0 |
2604 | * |
2605 | * Update a column with a Timestamp value. |
2606 | * |
2607 | * The updateXXX() methods are used to update column values in the current |
2608 | * row, or the insert row. The updateXXX() methods do not update the |
2609 | * underlying database, instead the updateRow() or insertRow() methods are |
2610 | * called to update the database. |
2611 | * |
2612 | * @param columnIndex |
2613 | * the first column is 1, the second is 2, ... |
2614 | * @param x |
2615 | * the new column value |
2616 | * @exception SQLException |
2617 | * if a database-access error occurs |
2618 | */ |
2619 | public void updateTimestamp(int columnIndex, java.sql.Timestamp x) |
2620 | throws SQLException { |
2621 | try { |
2622 | getDVDforColumnToBeUpdated(columnIndex, "updateTimestamp").setValue(x); |
2623 | } catch (StandardException t) { |
2624 | throw noStateChangeException(t); |
2625 | } |
2626 | } |
2627 | |
2628 | /** |
2629 | * JDBC 2.0 |
2630 | * |
2631 | * Update a column with an ascii stream value. |
2632 | * |
2633 | * The updateXXX() methods are used to update column values in the current |
2634 | * row, or the insert row. The updateXXX() methods do not update the |
2635 | * underlying database, instead the updateRow() or insertRow() methods are |
2636 | * called to update the database. |
2637 | * |
2638 | * @param columnIndex |
2639 | * the first column is 1, the second is 2, ... |
2640 | * @param x |
2641 | * the new column value |
2642 | * @param length |
2643 | * the length of the stream |
2644 | * @exception SQLException |
2645 | * if a database-access error occurs |
2646 | */ |
2647 | public void updateAsciiStream(int columnIndex, java.io.InputStream x, |
2648 | int length) throws SQLException { |
2649 | checksBeforeUpdateXXX("updateAsciiStream", columnIndex); |
2650 | |
2651 | int colType = getColumnType(columnIndex); |
2652 | switch (colType) { |
2653 | case Types.CHAR: |
2654 | case Types.VARCHAR: |
2655 | case Types.LONGVARCHAR: |
2656 | case Types.CLOB: |
2657 | break; |
2658 | default: |
2659 | throw dataTypeConversion(columnIndex, "java.io.InputStream"); |
2660 | } |
2661 | |
2662 | java.io.Reader r = null; |
2663 | if (x != null) |
2664 | { |
2665 | try { |
2666 | r = new java.io.InputStreamReader(x, "ISO-8859-1"); |
2667 | } catch (java.io.UnsupportedEncodingException uee) { |
2668 | throw new SQLException(uee.getMessage()); |
2669 | } |
2670 | } |
2671 | updateCharacterStream(columnIndex, r, length); |
2672 | } |
2673 | |
2674 | /** |
2675 | * JDBC 2.0 |
2676 | * |
2677 | * Update a column with a binary stream value. |
2678 | * |
2679 | * The updateXXX() methods are used to update column values in the current |
2680 | * row, or the insert row. The updateXXX() methods do not update the |
2681 | * underlying database, instead the updateRow() or insertRow() methods are |
2682 | * called to update the database. |
2683 | * |
2684 | * @param columnIndex |
2685 | * the first column is 1, the second is 2, ... |
2686 | * @param x |
2687 | * the new column value |
2688 | * @param length |
2689 | * the length of the stream |
2690 | * @exception SQLException |
2691 | * if a database-access error occurs |
2692 | */ |
2693 | public void updateBinaryStream(int columnIndex, java.io.InputStream x, |
2694 | int length) throws SQLException { |
2695 | checksBeforeUpdateXXX("updateBinaryStream", columnIndex); |
2696 | int colType = getColumnType(columnIndex); |
2697 | switch (colType) { |
2698 | case Types.BINARY: |
2699 | case Types.VARBINARY: |
2700 | case Types.LONGVARBINARY: |
2701 | case Types.BLOB: |
2702 | break; |
2703 | default: |
2704 | throw dataTypeConversion(columnIndex, "java.io.InputStream"); |
2705 | } |
2706 | |
2707 | if (x == null) |
2708 | { |
2709 | updateNull(columnIndex); |
2710 | return; |
2711 | } |
2712 | |
2713 | updateBinaryStreamInternal(columnIndex, x, length,"updateBinaryStream"); |
2714 | } |
2715 | |
2716 | private void updateBinaryStreamInternal(int columnIndex, |
2717 | java.io.InputStream x, long length, String updateMethodName) |
2718 | throws SQLException |
2719 | { |
2720 | if (length < 0) |
2721 | throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH); |
2722 | |
2723 | // max number of bytes that can be set to be inserted |
2724 | // in Derby is 2Gb-1 (ie Integer.MAX_VALUE). |
2725 | // (e.g into a blob column). |
2726 | if (length > Integer.MAX_VALUE ) { |
2727 | throw newSQLException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, |
2728 | getColumnSQLType(columnIndex)); |
2729 | } |
2730 | |
2731 | try { |
2732 | getDVDforColumnToBeUpdated(columnIndex, updateMethodName).setValue( |
2733 | new RawToBinaryFormatStream(x, (int) length), (int) length); |
2734 | } catch (StandardException t) { |
2735 | throw noStateChangeException(t); |
2736 | } |
2737 | } |
2738 | |
2739 | /** |
2740 | * JDBC 2.0 |
2741 | * |
2742 | * Update a column with a character stream value. |
2743 | * |
2744 | * The updateXXX() methods are used to update column values in the current |
2745 | * row, or the insert row. The updateXXX() methods do not update the |
2746 | * underlying database, instead the updateRow() or insertRow() methods are |
2747 | * called to update the database. |
2748 | * |
2749 | * @param columnIndex |
2750 | * the first column is 1, the second is 2, ... |
2751 | * @param x |
2752 | * the new column value |
2753 | * @param length |
2754 | * the length of the stream |
2755 | * @exception SQLException |
2756 | * if a database-access error occurs |
2757 | */ |
2758 | public void updateCharacterStream(int columnIndex, java.io.Reader x, |
2759 | int length) throws SQLException { |
2760 | //If the column type is the right datatype, this method will eventually call getDVDforColumnToBeUpdated which will check for |
2761 | //the read only resultset. But for other datatypes, we want to catch if this updateCharacterStream is being issued |
2762 | //against a read only resultset. And that is the reason for call to checksBeforeUpdateXXX here. |
2763 | checksBeforeUpdateXXX("updateCharacterStream", columnIndex); |
2764 | int colType = getColumnType(columnIndex); |
2765 | switch (colType) { |
2766 | case Types.CHAR: |
2767 | case Types.VARCHAR: |
2768 | case Types.LONGVARCHAR: |
2769 | case Types.CLOB: |
2770 | break; |
2771 | default: |
2772 | throw dataTypeConversion(columnIndex, "java.io.Reader"); |
2773 | } |
2774 | updateCharacterStreamInternal(columnIndex, x, length, "updateCharacterStream"); |
2775 | } |
2776 | |
2777 | private void updateCharacterStreamInternal(int columnIndex, |
2778 | java.io.Reader reader, long length, String updateMethodName) |
2779 | throws SQLException |
2780 | { |
2781 | try { |
2782 | |
2783 | if (reader == null) |
2784 | { |
2785 | updateNull(columnIndex); |
2786 | return; |
2787 | } |
2788 | |
2789 | // check for -ve length here |
2790 | if (length < 0) |
2791 | throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH); |
2792 | |
2793 | // max number of characters that can be set to be inserted |
2794 | // in Derby is 2Gb-1 (ie Integer.MAX_VALUE). |
2795 | // (e.g into a CLOB column). |
2796 | if (length > Integer.MAX_VALUE ) { |
2797 | throw newSQLException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, |
2798 | getColumnSQLType(columnIndex)); |
2799 | } |
2800 | |
2801 | // length is +ve. at this point, all checks for negative |
2802 | // length has already been done |
2803 | int usableLength = (int) length; |
2804 | int truncationLength = 0; |
2805 | |
2806 | // Currently long varchar does not allow for truncation of |
2807 | // trailing blanks. For char and varchar types, current mechanism |
2808 | // of materializing when using streams seems fine given their max |
2809 | // limits. This change is fix for DERBY-352: Insert of clobs using |
2810 | // streams should not materialize the entire stream into memory |
2811 | // In case of clobs, the truncation of trailing blanks is |
2812 | // factored in when reading from the stream without materializing |
2813 | // the entire stream, and so the special casing for clob below. |
2814 | if (getColumnType(columnIndex) == Types.CLOB) { |
2815 | // Need column width to figure out if truncation is |
2816 | // needed |
2817 | int colWidth = resultDescription.getColumnDescriptor( |
2818 | columnIndex).getType().getMaximumWidth(); |
2819 | |
2820 | // It is possible that the length of the stream passed |
2821 | // in is greater than the column width, in which case the data |
2822 | // from the stream needs to be truncated. |
2823 | // usableLength is the length of the data from stream |
2824 | // that can be used which is min(colWidth,length) provided |
2825 | // length - colWidth has trailing blanks only |
2826 | if (usableLength > colWidth) { |
2827 | truncationLength = usableLength - colWidth; |
2828 | usableLength = colWidth; |
2829 | } |
2830 | } |
2831 | |
2832 | ReaderToUTF8Stream utfIn = new ReaderToUTF8Stream( |
2833 | reader, usableLength, truncationLength); |
2834 | |
2835 | getDVDforColumnToBeUpdated(columnIndex, updateMethodName).setValue( |
2836 | utfIn, (int) usableLength); |
2837 | } catch (StandardException t) { |
2838 | throw noStateChangeException(t); |
2839 | } |
2840 | } |
2841 | |
2842 | /** |
2843 | * JDBC 2.0 |
2844 | * |
2845 | * Update a column with an Object value. |
2846 | * |
2847 | * The updateXXX() methods are used to update column values in the current |
2848 | * row, or the insert row. The updateXXX() methods do not update the |
2849 | * underlying database, instead the updateRow() or insertRow() methods are |
2850 | * called to update the database. |
2851 | * |
2852 | * @param columnIndex |
2853 | * the first column is 1, the second is 2, ... |
2854 | * @param x |
2855 | * the new column value |
2856 | * @param scale |
2857 | * For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types |
2858 | * this is the number of digits after the decimal. For all other |
2859 | * types this value will be ignored. |
2860 | * @exception SQLException |
2861 | * if a database-access error occurs |
2862 | */ |
2863 | public void updateObject(int columnIndex, Object x, int scale) |
2864 | throws SQLException { |
2865 | updateObject(columnIndex, x); |
2866 | /* |
2867 | * If the parameter type is DECIMAL or NUMERIC, then |
2868 | * we need to set them to the passed scale. |
2869 | */ |
2870 | int colType = getColumnType(columnIndex); |
2871 | if ((colType == Types.DECIMAL) || (colType == Types.NUMERIC)) { |
2872 | if (scale < 0) |
2873 | throw newSQLException(SQLState.BAD_SCALE_VALUE, new Integer(scale)); |
2874 | |
2875 | try { |
2876 | DataValueDescriptor value = updateRow.getColumn(columnIndex); |
2877 | |
2878 | int origvaluelen = value.getLength(); |
2879 | ((VariableSizeDataValue) |
2880 | value).setWidth(VariableSizeDataValue.IGNORE_PRECISION, |
2881 | scale, |
2882 | false); |
2883 | |
2884 | } catch (StandardException t) { |
2885 | throw EmbedResultSet.noStateChangeException(t); |
2886 | } |
2887 | } |
2888 | } |
2889 | |
2890 | /** |
2891 | * JDBC 2.0 |
2892 | * |
2893 | * Update a column with an Object value. |
2894 | * |
2895 | * The updateXXX() methods are used to update column values in the current |
2896 | * row, or the insert row. The updateXXX() methods do not update the |
2897 | * underlying database, instead the updateRow() or insertRow() methods are |
2898 | * called to update the database. |
2899 | * |
2900 | * @param columnIndex |
2901 | * the first column is 1, the second is 2, ... |
2902 | * @param x |
2903 | * the new column value |
2904 | * @exception SQLException |
2905 | * if a database-access error occurs |
2906 | */ |
2907 | public void updateObject(int columnIndex, Object x) throws SQLException { |
2908 | checksBeforeUpdateXXX("updateObject", columnIndex); |
2909 | int colType = getColumnType(columnIndex); |
2910 | if (colType == org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT) { |
2911 | try { |
2912 | ((UserDataValue) getDVDforColumnToBeUpdated(columnIndex, "updateObject")).setValue(x); |
2913 | return; |
2914 | } catch (StandardException t) { |
2915 | throw noStateChangeException(t); |
2916 | } |
2917 | } |
2918 | |
2919 | if (x == null) { |
2920 | updateNull(columnIndex); |
2921 | return; |
2922 | } |
2923 | |
2924 | if (x instanceof String) { |
2925 | updateString(columnIndex, (String) x); |
2926 | return; |
2927 | } |
2928 | |
2929 | if (x instanceof Boolean) { |
2930 | updateBoolean(columnIndex, ((Boolean) x).booleanValue()); |
2931 | return; |
2932 | } |
2933 | |
2934 | if (x instanceof Short) { |
2935 | updateShort(columnIndex, ((Short) x).shortValue()); |
2936 | return; |
2937 | } |
2938 | |
2939 | if (x instanceof Integer) { |
2940 | updateInt(columnIndex, ((Integer) x).intValue()); |
2941 | return; |
2942 | } |
2943 | |
2944 | if (x instanceof Long) { |
2945 | updateLong(columnIndex, ((Long) x).longValue()); |
2946 | return; |
2947 | } |
2948 | |
2949 | if (x instanceof Float) { |
2950 | updateFloat(columnIndex, ((Float) x).floatValue()); |
2951 | return; |
2952 | } |
2953 | |
2954 | if (x instanceof Double) { |
2955 | updateDouble(columnIndex, ((Double) x).doubleValue()); |
2956 | return; |
2957 | } |
2958 | |
2959 | if (x instanceof byte[]) { |
2960 | updateBytes(columnIndex, (byte[]) x); |
2961 | return; |
2962 | } |
2963 | |
2964 | if (x instanceof Date) { |
2965 | updateDate(columnIndex, (Date) x); |
2966 | return; |
2967 | } |
2968 | |
2969 | if (x instanceof Time) { |
2970 | updateTime(columnIndex, (Time) x); |
2971 | return; |
2972 | } |
2973 | |
2974 | if (x instanceof Timestamp) { |
2975 | updateTimestamp(columnIndex, (Timestamp) x); |
2976 | return; |
2977 | } |
2978 | |
2979 | if (x instanceof Blob) { |
2980 | updateBlob(columnIndex, (Blob) x); |
2981 | return; |
2982 | } |
2983 | |
2984 | if (x instanceof Clob) { |
2985 | updateClob(columnIndex, (Clob) x); |
2986 | return; |
2987 | } |
2988 | |
2989 | throw dataTypeConversion(columnIndex, x.getClass().getName()); |
2990 | } |
2991 | |
2992 | /** |
2993 | * JDBC 2.0 |
2994 | * |
2995 | * Update a column with a null value. |
2996 | * |
2997 | * The updateXXX() methods are used to update column values in the current |
2998 | * row, or the insert row. The updateXXX() methods do not update the |
2999 | * underlying database, instead the updateRow() or insertRow() methods are |
3000 | * called to update the database. |
3001 | * |
3002 | * @param columnName |
3003 | * the name of the column |
3004 | * @exception SQLException |
3005 | * if a database-access error occurs |
3006 | */ |
3007 | public void updateNull(String columnName) throws SQLException { |
3008 | checkIfClosed("updateNull"); |
3009 | updateNull(findColumnName(columnName)); |
3010 | } |
3011 | |
3012 | /** |
3013 | * JDBC 2.0 |
3014 | * |
3015 | * Update a column with a boolean value. |
3016 | * |
3017 | * The updateXXX() methods are used to update column values in the current |
3018 | * row, or the insert row. The updateXXX() methods do not update the |
3019 | * underlying database, instead the updateRow() or insertRow() methods are |
3020 | * called to update the database. |
3021 | * |
3022 | * @param columnName |
3023 | * the name of the column |
3024 | * @param x |
3025 | * the new column value |
3026 | * @exception SQLException |
3027 | * if a database-access error occurs |
3028 | */ |
3029 | public void updateBoolean(String columnName, boolean x) throws SQLException { |
3030 | checkIfClosed("updateBoolean"); |
3031 | updateBoolean(findColumnName(columnName), x); |
3032 | } |
3033 | |
3034 | /** |
3035 | * JDBC 2.0 |
3036 | * |
3037 | * Update a column with a byte value. |
3038 | * |
3039 | * The updateXXX() methods are used to update column values in the current |
3040 | * row, or the insert row. The updateXXX() methods do not update the |
3041 | * underlying database, instead the updateRow() or insertRow() methods are |
3042 | * called to update the database. |
3043 | * |
3044 | * @param columnName |
3045 | * the name of the column |
3046 | * @param x |
3047 | * the new column value |
3048 | * @exception SQLException |
3049 | * if a database-access error occurs |
3050 | */ |
3051 | public void updateByte(String columnName, byte x) throws SQLException { |
3052 | checkIfClosed("updateByte"); |
3053 | updateByte(findColumnName(columnName), x); |
3054 | } |
3055 | |
3056 | /** |
3057 | * JDBC 2.0 |
3058 | * |
3059 | * Update a column with a short value. |
3060 | * |
3061 | * The updateXXX() methods are used to update column values in the current |
3062 | * row, or the insert row. The updateXXX() methods do not update the |
3063 | * underlying database, instead the updateRow() or insertRow() methods are |
3064 | * called to update the database. |
3065 | * |
3066 | * @param columnName |
3067 | * the name of the column |
3068 | * @param x |
3069 | * the new column value |
3070 | * @exception SQLException |
3071 | * if a database-access error occurs |
3072 | */ |
3073 | public void updateShort(String columnName, short x) throws SQLException { |
3074 | checkIfClosed("updateShort"); |
3075 | updateShort(findColumnName(columnName), x); |
3076 | } |
3077 | |
3078 | /** |
3079 | * JDBC 2.0 |
3080 | * |
3081 | * Update a column with an integer value. |
3082 | * |
3083 | * The updateXXX() methods are used to update column values in the current |
3084 | * row, or the insert row. The updateXXX() methods do not update the |
3085 | * underlying database, instead the updateRow() or insertRow() methods are |
3086 | * called to update the database. |
3087 | * |
3088 | * @param columnName |
3089 | * the name of the column |
3090 | * @param x |
3091 | * the new column value |
3092 | * @exception SQLException |
3093 | * if a database-access error occurs |
3094 | */ |
3095 | public void updateInt(String columnName, int x) throws SQLException { |
3096 | checkIfClosed("updateInt"); |
3097 | updateInt(findColumnName(columnName), x); |
3098 | } |
3099 | |
3100 | /** |
3101 | * JDBC 2.0 |
3102 | * |
3103 | * Update a column with a long value. |
3104 | * |
3105 | * The updateXXX() methods are used to update column values in the current |
3106 | * row, or the insert row. The updateXXX() methods do not update the |
3107 | * underlying database, instead the updateRow() or insertRow() methods are |
3108 | * called to update the database. |
3109 | * |
3110 | * @param columnName |
3111 | * the name of the column |
3112 | * @param x |
3113 | * the new column value |
3114 | * @exception SQLException |
3115 | * if a database-access error occurs |
3116 | */ |
3117 | public void updateLong(String columnName, long x) throws SQLException { |
3118 | checkIfClosed("updateLong"); |
3119 | updateLong(findColumnName(columnName), x); |
3120 | } |
3121 | |
3122 | /** |
3123 | * JDBC 2.0 |
3124 | * |
3125 | * Update a column with a float value. |
3126 | * |
3127 | * The updateXXX() methods are used to update column values in the current |
3128 | * row, or the insert row. The updateXXX() methods do not update the |
3129 | * underlying database, instead the updateRow() or insertRow() methods are |
3130 | * called to update the database. |
3131 | * |
3132 | * @param columnName |
3133 | * the name of the column |
3134 | * @param x |
3135 | * the new column value |
3136 | * @exception SQLException |
3137 | * if a database-access error occurs |
3138 | */ |
3139 | public void updateFloat(String columnName, float x) throws SQLException { |
3140 | checkIfClosed("updateFloat"); |
3141 | updateFloat(findColumnName(columnName), x); |
3142 | } |
3143 | |
3144 | /** |
3145 | * JDBC 2.0 |
3146 | * |
3147 | * Update a column with a double value. |
3148 | * |
3149 | * The updateXXX() methods are used to update column values in the current |
3150 | * row, or the insert row. The updateXXX() methods do not update the |
3151 | * underlying database, instead the updateRow() or insertRow() methods are |
3152 | * called to update the database. |
3153 | * |
3154 | * @param columnName |
3155 | * the name of the column |
3156 | * @param x |
3157 | * the new column value |
3158 | * @exception SQLException |
3159 | * if a database-access error occurs |
3160 | */ |
3161 | public void updateDouble(String columnName, double x) throws SQLException { |
3162 | checkIfClosed("updateDouble"); |
3163 | updateDouble(findColumnName(columnName), x); |
3164 | } |
3165 | |
3166 | /** |
3167 | * JDBC 2.0 |
3168 | * |
3169 | * Update a column with a String value. |
3170 | * |
3171 | * The updateXXX() methods are used to update column values in the current |
3172 | * row, or the insert row. The updateXXX() methods do not update the |
3173 | * underlying database, instead the updateRow() or insertRow() methods are |
3174 | * called to update the database. |
3175 | * |
3176 | * @param columnName |
3177 | * the name of the column |
3178 | * @param x |
3179 | * the new column value |
3180 | * @exception SQLException |
3181 | * if a database-access error occurs |
3182 | */ |
3183 | public void updateString(String columnName, String x) throws SQLException { |
3184 | checkIfClosed("updateString"); |
3185 | updateString(findColumnName(columnName), x); |
3186 | } |
3187 | |
3188 | /** |
3189 | * JDBC 2.0 |
3190 | * |
3191 | * Update a column with a byte array value. |
3192 | * |
3193 | * The updateXXX() methods are used to update column values in the current |
3194 | * row, or the insert row. The updateXXX() methods do not update the |
3195 | * underlying database, instead the updateRow() or insertRow() methods are |
3196 | * called to update the database. |
3197 | * |
3198 | * @param columnName |
3199 | * the name of the column |
3200 | * @param x |
3201 | * the new column value |
3202 | * @exception SQLException |
3203 | * if a database-access error occurs |
3204 | */ |
3205 | public void updateBytes(String columnName, byte x[]) throws SQLException { |
3206 | checkIfClosed("updateBytes"); |
3207 | updateBytes(findColumnName(columnName), x); |
3208 | } |
3209 | |
3210 | /** |
3211 | * JDBC 2.0 |
3212 | * |
3213 | * Update a column with a Date value. |
3214 | * |
3215 | * The updateXXX() methods are used to update column values in the current |
3216 | * row, or the insert row. The updateXXX() methods do not update the |
3217 | * underlying database, instead the updateRow() or insertRow() methods are |
3218 | * called to update the database. |
3219 | * |
3220 | * @param columnName |
3221 | * the name of the column |
3222 | * @param x |
3223 | * the new column value |
3224 | * @exception SQLException |
3225 | * if a database-access error occurs |
3226 | */ |
3227 | public void updateDate(String columnName, java.sql.Date x) |
3228 | throws SQLException { |
3229 | checkIfClosed("updateDate"); |
3230 | updateDate(findColumnName(columnName), x); |
3231 | } |
3232 | |
3233 | /** |
3234 | * JDBC 2.0 |
3235 | * |
3236 | * Update a column with a Time value. |
3237 | * |
3238 | * The updateXXX() methods are used to update column values in the current |
3239 | * row, or the insert row. The updateXXX() methods do not update the |
3240 | * underlying database, instead the updateRow() or insertRow() methods are |
3241 | * called to update the database. |
3242 | * |
3243 | * @param columnName |
3244 | * the name of the column |
3245 | * @param x |
3246 | * the new column value |
3247 | * @exception SQLException |
3248 | * if a database-access error occurs |
3249 | */ |
3250 | public void updateTime(String columnName, java.sql.Time x) |
3251 | throws SQLException { |
3252 | checkIfClosed("updateTime"); |
3253 | updateTime(findColumnName(columnName), x); |
3254 | } |
3255 | |
3256 | /** |
3257 | * JDBC 2.0 |
3258 | * |
3259 | * Update a column with a Timestamp value. |
3260 | * |
3261 | * The updateXXX() methods are used to update column values in the current |
3262 | * row, or the insert row. The updateXXX() methods do not update the |
3263 | * underlying database, instead the updateRow() or insertRow() methods are |
3264 | * called to update the database. |
3265 | * |
3266 | * @param columnName |
3267 | * the name of the column |
3268 | * @param x |
3269 | * the new column value |
3270 | * @exception SQLException |
3271 | * if a database-access error occurs |
3272 | */ |
3273 | public void updateTimestamp(String columnName, java.sql.Timestamp x) |
3274 | throws SQLException { |
3275 | checkIfClosed("updateTimestamp"); |
3276 | updateTimestamp(findColumnName(columnName), x); |
3277 | } |
3278 | |
3279 | /** |
3280 | * JDBC 2.0 |
3281 | * |
3282 | * Update a column with an ascii stream value. |
3283 | * |
3284 | * The updateXXX() methods are used to update column values in the current |
3285 | * row, or the insert row. The updateXXX() methods do not update the |
3286 | * underlying database, instead the updateRow() or insertRow() methods are |
3287 | * called to update the database. |
3288 | * |
3289 | * @param columnName |
3290 | * the name of the column |
3291 | * @param x |
3292 | * the new column value |
3293 | * @param length |
3294 | * of the stream |
3295 | * @exception SQLException |
3296 | * if a database-access error occurs |
3297 | */ |
3298 | public void updateAsciiStream(String columnName, java.io.InputStream x, |
3299 | int length) throws SQLException { |
3300 | checkIfClosed("updateAsciiStream"); |
3301 | updateAsciiStream(findColumnName(columnName), x, length); |
3302 | } |
3303 | |
3304 | /** |
3305 | * JDBC 2.0 |
3306 | * |
3307 | * Update a column with a binary stream value. |
3308 | * |
3309 | * The updateXXX() methods are used to update column values in the current |
3310 | * row, or the insert row. The updateXXX() methods do not update the |
3311 | * underlying database, instead the updateRow() or insertRow() methods are |
3312 | * called to update the database. |
3313 | * |
3314 | * @param columnName |
3315 | * the name of the column |
3316 | * @param x |
3317 | * the new column value |
3318 | * @param length |
3319 | * of the stream |
3320 | * @exception SQLException |
3321 | * if a database-access error occurs |
3322 | */ |
3323 | public void updateBinaryStream(String columnName, java.io.InputStream x, |
3324 | int length) throws SQLException { |
3325 | checkIfClosed("updateBinaryStream"); |
3326 | updateBinaryStream(findColumnName(columnName), x, length); |
3327 | } |
3328 | |
3329 | /** |
3330 | * JDBC 2.0 |
3331 | * |
3332 | * Update a column with a character stream value. |
3333 | * |
3334 | * The updateXXX() methods are used to update column values in the current |
3335 | * row, or the insert row. The updateXXX() methods do not update the |
3336 | * underlying database, instead the updateRow() or insertRow() methods are |
3337 | * called to update the database. |
3338 | * |
3339 | * @param columnName |
3340 | * the name of the column |
3341 | * @param reader |
3342 | * the new column value |
3343 | * @param length |
3344 | * length of the stream |
3345 | * @exception SQLException |
3346 | * if a database-access error occurs |
3347 | */ |
3348 | public void updateCharacterStream(String columnName, java.io.Reader reader, |
3349 | int length) throws SQLException { |
3350 | checkIfClosed("updateCharacterStream"); |
3351 | updateCharacterStream(findColumnName(columnName), reader, length); |
3352 | } |
3353 | |
3354 | /** |
3355 | * JDBC 2.0 |
3356 | * |
3357 | * Update a column with an Object value. |
3358 | * |
3359 | * The updateXXX() methods are used to update column values in the |
3360 | * current row, or the insert row. The updateXXX() methods do not |
3361 | * update the underlying database, instead the updateRow() or insertRow() |
3362 | * methods are called to update the database. |
3363 | * |
3364 | * @param columnName the name of the column |
3365 | * @param x the new column value |
3366 | * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types |
3367 | * this is the number of digits after the decimal. For all other |
3368 | * types this value will be ignored. |
3369 | * @exception SQLException if a database-access error occurs |
3370 | */ |
3371 | public void updateObject(String columnName, Object x, int scale) |
3372 | throws SQLException { |
3373 | checkIfClosed("updateObject"); |
3374 | updateObject(findColumnName(columnName), x, scale); |
3375 | } |
3376 | |
3377 | /** |
3378 | * JDBC 2.0 |
3379 | * |
3380 | * Update a column with an Object value. |
3381 | * |
3382 | * The updateXXX() methods are used to update column values in the current |
3383 | * row, or the insert row. The updateXXX() methods do not update the |
3384 | * underlying database, instead the updateRow() or insertRow() methods are |
3385 | * called to update the database. |
3386 | * |
3387 | * @param columnName |
3388 | * the name of the column |
3389 | * @param x |
3390 | * the new column value |
3391 | * @exception SQLException |
3392 | * if a database-access error occurs |
3393 | */ |
3394 | public void updateObject(String columnName, Object x) throws SQLException { |
3395 | checkIfClosed("updateObject"); |
3396 | updateObject(findColumnName(columnName), x); |
3397 | } |
3398 | |
3399 | /** |
3400 | * JDBC 2.0 |
3401 | * |
3402 | * Insert the contents of the insert row into the result set and the |
3403 | * database. Must be on the insert row when this method is called. |
3404 | * |
3405 | * @exception SQLException |
3406 | * if a database-access error occurs, if called when not on |
3407 | * the insert row, or if all non-nullable columns in the |
3408 | * insert row have not been given a value |
3409 | */ |
3410 | public void insertRow() throws SQLException { |
3411 | synchronized (getConnectionSynchronization()) { |
3412 | checksBeforeInsert(); |
3413 | setupContextStack(); |
3414 | LanguageConnectionContext lcc = null; |
3415 | StatementContext statementContext = null; |
3416 | try { |
3417 | /* |
3418 | * construct the insert statement |
3419 | * |
3420 | * If no values have been supplied for a column, it will be set |
3421 | * to the column's default value, if any. |
3422 | * If no default value had been defined, the default value of a |
3423 | * nullable column is set to NULL. |
3424 | */ |
3425 | |
3426 | boolean foundOneColumnAlready = false; |
3427 | StringBuffer insertSQL = new StringBuffer("INSERT INTO "); |
3428 | StringBuffer valuesSQL = new StringBuffer("VALUES ("); |
3429 | CursorActivation activation = getEmbedConnection(). |
3430 | getLanguageConnection().lookupCursorActivation(getCursorName()); |
3431 | |
3432 | ExecCursorTableReference targetTable = |
3433 | activation.getPreparedStatement().getTargetTable(); |
3434 | // got the underlying (schema.)table name |
3435 | insertSQL.append(getFullBaseTableName(targetTable)); |
3436 | ResultDescription rd = theResults.getResultDescription(); |
3437 | |
3438 | insertSQL.append(" ("); |
3439 | // in this for loop we are constructing list of column-names |
3440 | // and values (?) ,... part of the insert sql |
3441 | for (int i=1; i<=rd.getColumnCount(); i++) { |
3442 | if (foundOneColumnAlready) { |
3443 | insertSQL.append(","); |
3444 | valuesSQL.append(","); |
3445 | } |
3446 | // using quotes around the column name |
3447 | // to preserve case sensitivity |
3448 | insertSQL.append("\"" + |
3449 | rd.getColumnDescriptor(i).getName() + "\""); |
3450 | if (columnGotUpdated[i-1]) { |
3451 | valuesSQL.append("?"); |
3452 | } else { |
3453 | valuesSQL.append("DEFAULT"); |
3454 | } |
3455 | foundOneColumnAlready = true; |
3456 | } |
3457 | insertSQL.append(") "); |
3458 | valuesSQL.append(") "); |
3459 | insertSQL.append(valuesSQL); |
3460 | |
3461 | lcc = getEmbedConnection().getLanguageConnection(); |
3462 | |
3463 | // Context used for preparing, don't set any timeout (use 0) |
3464 | statementContext = lcc.pushStatementContext( |
3465 | isAtomic, |
3466 | false, |
3467 | insertSQL.toString(), |
3468 | null, |
3469 | false, |
3470 | 0L); |
3471 | org.apache.derby.iapi.sql.PreparedStatement ps = |
3472 | lcc.prepareInternalStatement(insertSQL.toString()); |
3473 | Activation act = ps.getActivation(lcc, false); |
3474 | |
3475 | // in this for loop we are assigning values for parameters |
3476 | //in sql constructed earlier VALUES (?, ..) |
3477 | for (int i=1, paramPosition=0; i<=rd.getColumnCount(); i++) { |
3478 | // if the column got updated, do following |
3479 | if (columnGotUpdated[i-1]) { |
3480 | act.getParameterValueSet(). |
3481 | getParameterForSet(paramPosition++). |
3482 | setValue(updateRow.getColumn(i)); |
3483 | } |
3484 | } |
3485 | // Don't see any timeout when inserting rows (use 0) |
3486 | //execute the insert |
3487 | org.apache.derby.iapi.sql.ResultSet rs = |
3488 | ps.execute(act, true, 0L); |
3489 | rs.close(); |
3490 | rs.finish(); |
3491 | |
3492 | lcc.popStatementContext(statementContext, null); |
3493 | } catch (StandardException t) { |
3494 | throw closeOnTransactionError(t); |
3495 | } finally { |
3496 | restoreContextStack(); |
3497 | } |
3498 | } |
3499 | } |
3500 | |
3501 | /** |
3502 | * JDBC 2.0 |
3503 | * |
3504 | * Update the underlying database with the new contents of the |
3505 | * current row. Cannot be called when on the insert row. |
3506 | * |
3507 | * @exception SQLException if a database-access error occurs, or |
3508 | * if called when on the insert row |
3509 | */ |
3510 | public void updateRow() throws SQLException { |
3511 | synchronized (getConnectionSynchronization()) { |
3512 | checksBeforeUpdateOrDelete("updateRow", -1); |
3513 | |
3514 | // Check that the cursor is not positioned on insertRow |
3515 | checkNotOnInsertRow(); |
3516 | |
3517 | setupContextStack(); |
3518 | LanguageConnectionContext lcc = null; |
3519 | StatementContext statementContext = null; |
3520 | try { |
3521 | if (currentRowHasBeenUpdated == false) //nothing got updated on this row |
3522 | return; //nothing to do since no updates were made to this row |
3523 | |
3524 | //now construct the update where current of sql |
3525 | boolean foundOneColumnAlready = false; |
3526 | StringBuffer updateWhereCurrentOfSQL = new StringBuffer("UPDATE "); |
3527 | CursorActivation activation = getEmbedConnection().getLanguageConnection().lookupCursorActivation(getCursorName()); |
3528 | |
3529 | |
3530 | ExecCursorTableReference targetTable = activation.getPreparedStatement().getTargetTable(); |
3531 | updateWhereCurrentOfSQL.append(getFullBaseTableName(targetTable));//got the underlying (schema.)table name |
3532 | updateWhereCurrentOfSQL.append(" SET "); |
3533 | ResultDescription rd = theResults.getResultDescription(); |
3534 | |
3535 | for (int i=1; i<=rd.getColumnCount(); i++) { //in this for loop we are constructing columnname=?,... part of the update sql |
3536 | if (columnGotUpdated[i-1]) { //if the column got updated, do following |
3537 | if (foundOneColumnAlready) |
3538 | updateWhereCurrentOfSQL.append(","); |
3539 | //using quotes around the column name to preserve case sensitivity |
3540 | updateWhereCurrentOfSQL.append("\"" + rd.getColumnDescriptor(i).getName() + "\"=?"); |
3541 | foundOneColumnAlready = true; |
3542 | } |
3543 | } |
3544 | //using quotes around the cursor name to preserve case sensitivity |
3545 | updateWhereCurrentOfSQL.append(" WHERE CURRENT OF \"" + getCursorName() + "\""); |
3546 | lcc = getEmbedConnection().getLanguageConnection(); |
3547 | |
3548 | // Context used for preparing, don't set any timeout (use 0) |
3549 | statementContext = lcc.pushStatementContext(isAtomic, false, updateWhereCurrentOfSQL.toString(), null, false, 0L); |
3550 | org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(updateWhereCurrentOfSQL.toString()); |
3551 | Activation act = ps.getActivation(lcc, false); |
3552 | |
3553 | //in this for loop we are assigning values for parameters in sql constructed earlier with columnname=?,... |
3554 | for (int i=1, paramPosition=0; i<=rd.getColumnCount(); i++) { |
3555 | if (columnGotUpdated[i-1]) //if the column got updated, do following |
3556 | act.getParameterValueSet().getParameterForSet(paramPosition++).setValue(updateRow.getColumn(i)); |
3557 | } |
3558 | // Don't set any timeout when updating rows (use 0) |
3559 | // Execute the update where current of sql. |
3560 | org.apache.derby.iapi.sql.ResultSet rs = ps.execute(act, true, 0L); |
3561 | SQLWarning w = act.getWarnings(); |
3562 | if (w != null) { |
3563 | addWarning(w); |
3564 | } |
3565 | rs.close(); |
3566 | rs.finish(); |
3567 | //For forward only resultsets, after a update, the ResultSet will be positioned right before the next row. |
3568 | if (getType() == TYPE_FORWARD_ONLY) { |
3569 | currentRow.setRowArray(null); |
3570 | } else { |
3571 | movePosition(RELATIVE, 0, "relative"); |
3572 | } |
3573 | lcc.popStatementContext(statementContext, null); |
3574 | } catch (StandardException t) { |
3575 | throw closeOnTransactionError(t); |
3576 | } finally { |
3577 | if (statementContext != null) |
3578 | lcc.popStatementContext(statementContext, null); |
3579 | restoreContextStack(); |
3580 | initializeUpdateRowModifiers(); |
3581 | } |
3582 | } |
3583 | } |
3584 | |
3585 | /** |
3586 | * JDBC 2.0 |
3587 | * |
3588 | * Delete the current row from the result set and the underlying |
3589 | * database. Cannot be called when on the insert row. |
3590 | * |
3591 | * @exception SQLException if a database-access error occurs, or if |
3592 | * called when on the insert row. |
3593 | */ |
3594 | public void deleteRow() throws SQLException { |
3595 | synchronized (getConnectionSynchronization()) { |
3596 | checksBeforeUpdateOrDelete("deleteRow", -1); |
3597 | |
3598 | // Check that the cursor is not positioned on insertRow |
3599 | checkNotOnInsertRow(); |
3600 | |
3601 | setupContextStack(); |
3602 | //now construct the delete where current of sql |
3603 | try { |
3604 | StringBuffer deleteWhereCurrentOfSQL = new StringBuffer("DELETE FROM "); |
3605 | CursorActivation activation = getEmbedConnection().getLanguageConnection().lookupCursorActivation(getCursorName()); |
3606 | deleteWhereCurrentOfSQL.append(getFullBaseTableName(activation.getPreparedStatement().getTargetTable()));//get the underlying (schema.)table name |
3607 | //using quotes around the cursor name to preserve case sensitivity |
3608 | deleteWhereCurrentOfSQL.append(" WHERE CURRENT OF \"" + getCursorName() + "\""); |
3609 | |
3610 | LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection(); |
3611 | |
3612 | // Context used for preparing, don't set any timeout (use 0) |
3613 | StatementContext statementContext = lcc.pushStatementContext(isAtomic, false, deleteWhereCurrentOfSQL.toString(), null, false, 0L); |
3614 | org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(deleteWhereCurrentOfSQL.toString()); |
3615 | // Get activation, so that we can get the warning from it |
3616 | Activation act = ps.getActivation(lcc, false); |
3617 | // Don't set any timeout when deleting rows (use 0) |
3618 | //execute delete where current of sql |
3619 | org.apache.derby.iapi.sql.ResultSet rs = |
3620 | ps.execute(act, true, 0L); |
3621 | SQLWarning w = act.getWarnings(); |
3622 | if (w != null) { |
3623 | addWarning(w); |
3624 | } |
3625 | rs.close(); |
3626 | rs.finish(); |
3627 | //After a delete, the ResultSet will be positioned right before |
3628 | //the next row. |
3629 | currentRow.setRowArray(null); |
3630 | lcc.popStatementContext(statementContext, null); |
3631 | } catch (StandardException t) { |
3632 | throw closeOnTransactionError(t); |
3633 | } finally { |
3634 | restoreContextStack(); |
3635 | initializeUpdateRowModifiers(); |
3636 | } |
3637 | } |
3638 | } |
3639 | |
3640 | private String getFullBaseTableName(ExecCursorTableReference targetTable) { |
3641 | //using quotes to preserve case sensitivity |
3642 | if (targetTable.getSchemaName() != null) |
3643 | return "\"" + targetTable.getSchemaName() + "\".\"" |
3644 | + targetTable.getBaseName() + "\""; |
3645 | else |
3646 | return "\"" + targetTable.getBaseName() + "\""; |
3647 | } |
3648 | |
3649 | /** |
3650 | * JDBC 2.0 |
3651 | * |
3652 | * Refresh the value of the current row with its current value in the |
3653 | * database. Cannot be called when on the insert row. |
3654 | * |
3655 | * The refreshRow() method provides a way for an application to explicitly |
3656 | * tell the JDBC driver to refetch a row(s) from the database. An |
3657 | * application may want to call refreshRow() when caching or prefetching is |
3658 | * being done by the JDBC driver to fetch the latest value of a row from the |
3659 | * database. The JDBC driver may actually refresh multiple rows at once if |
3660 | * the fetch size is greater than one. |
3661 | * |
3662 | * All values are refetched subject to the transaction isolation level and |
3663 | * cursor sensitivity. If refreshRow() is called after calling updateXXX(), |
3664 | * but before calling updateRow() then the updates made to the row are lost. |
3665 | * Calling refreshRow() frequently will likely slow performance. |
3666 | * |
3667 | * @exception SQLException |
3668 | * if a database-access error occurs, or if called when on |
3669 | * the insert row. |
3670 | */ |
3671 | public void refreshRow() throws SQLException { |
3672 | throw Util.notImplemented(); |
3673 | } |
3674 | |
3675 | /** |
3676 | * JDBC 2.0 |
3677 | * |
3678 | * The cancelRowUpdates() method may be called after calling an |
3679 | * updateXXX() method(s) and before calling updateRow() to rollback |
3680 | * the updates made to a row. If no updates have been made or |
3681 | * updateRow() has already been called, then this method has no |
3682 | * effect. |
3683 | * |
3684 | * @exception SQLException if a database-access error occurs, or if |
3685 | * called when on the insert row. |
3686 | * |
3687 | */ |
3688 | public void cancelRowUpdates () throws SQLException { |
3689 | checksBeforeUpdateOrDelete("cancelRowUpdates", -1); |
3690 | |
3691 | checkNotOnInsertRow(); |
3692 | |
3693 | initializeUpdateRowModifiers(); |
3694 | } |
3695 | |
3696 | /** |
3697 | * JDBC 2.0 |
3698 | * |
3699 | * Move to the insert row. The current cursor position is remembered while |
3700 | * the cursor is positioned on the insert row. |
3701 | * |
3702 | * The insert row is a special row associated with an updatable result set. |
3703 | * It is essentially a buffer where a new row may be constructed by calling |
3704 | * the updateXXX() methods prior to inserting the row into the result set. |
3705 | * |
3706 | * Only the updateXXX(), getXXX(), and insertRow() methods may be called |
3707 | * when the cursor is on the insert row. All of the columns in a result set |
3708 | * must be given a value each time this method is called before calling |
3709 | * insertRow(). UpdateXXX()must be called before getXXX() on a column. |
3710 | * |
3711 | * @exception SQLException |
3712 | * if a database-access error occurs, or the result set is |
3713 | * not updatable |
3714 | */ |
3715 | public void moveToInsertRow() throws SQLException { |
3716 | checkExecIfClosed("moveToInsertRow"); |
3717 | |
3718 | // if not updatable resultset, then throw exception |
3719 | checkUpdatableCursor("moveToInsertRow"); |
3720 | |
3721 | synchronized (getConnectionSynchronization()) { |
3722 | try { |
3723 | // initialize state corresponding to insertRow/updateRow impl. |
3724 | initializeUpdateRowModifiers(); |
3725 | isOnInsertRow = true; |
3726 | |
3727 | for (int i=1; i <= columnGotUpdated.length; i++) { |
3728 | updateRow.setColumn(i, |
3729 | resultDescription.getColumnDescriptor(i).getType().getNull()); |
3730 | } |
3731 | } catch (Throwable ex) { |
3732 | handleException(ex); |
3733 | } |
3734 | } |
3735 | } |
3736 | |
3737 | /** |
3738 | * JDBC 2.0 |
3739 | * |
3740 | * Move the cursor to the remembered cursor position, usually the current |
3741 | * row. Has no effect unless the cursor is on the insert row. |
3742 | * |
3743 | * @exception SQLException |
3744 | * if a database-access error occurs, or the result set is |
3745 | * not updatable |
3746 | */ |
3747 | public void moveToCurrentRow() throws SQLException { |
3748 | checkExecIfClosed("moveToCurrentRow"); |
3749 | |
3750 | // if not updatable resultset, then throw exception |
3751 | checkUpdatableCursor("moveToCurrentRow"); |
3752 | |
3753 | synchronized (getConnectionSynchronization()) { |
3754 | try { |
3755 | |
3756 | if (isOnInsertRow) { |
3757 | // initialize state corresponding to insertRow/updateRow impl. |
3758 | initializeUpdateRowModifiers(); |
3759 | |
3760 | isOnInsertRow = false; |
3761 | } |
3762 | } catch (Throwable ex) { |
3763 | handleException(ex); |
3764 | } |
3765 | } |
3766 | } |
3767 | |
3768 | /** |
3769 | * JDBC 2.0 |
3770 | * |
3771 | * Get a BLOB column. |
3772 | * |
3773 | * @param columnIndex the first column is 1, the second is 2, ... |
3774 | * @return an object representing a BLOB |
3775 | */ |
3776 | public Blob getBlob(int columnIndex) throws SQLException { |
3777 | |
3778 | closeCurrentStream(); // closing currentStream does not depend on the |
3779 | // underlying connection. Do this outside of |
3780 | // the connection synchronization. |
3781 | |
3782 | checkIfClosed("getBlob"); // checking result set closure does not depend |
3783 | // on the underlying connection. Do this |
3784 | // outside of the connection synchronization. |
3785 | |
3786 | synchronized (getConnectionSynchronization()) { |
3787 | int colType = getColumnType(columnIndex); |
3788 | |
3789 | // DB2, only allow getBlob on a BLOB column. |
3790 | if (colType != Types.BLOB) |
3791 | throw dataTypeConversion("java.sql.Blob", columnIndex); |
3792 | |
3793 | boolean pushStack = false; |
3794 | try { |
3795 | DataValueDescriptor dvd = getColumn(columnIndex); |
3796 | |
3797 | if (wasNull = dvd.isNull()) |
3798 | return null; |
3799 | |
3800 | // should set up a context stack if we have a long column, |
3801 | // since a blob may keep a pointer to a long column in the |
3802 | // database |
3803 | if (dvd.getStream() != null) |
3804 | pushStack = true; |
3805 | |
3806 | if (pushStack) |
3807 | setupContextStack(); |
3808 | |
3809 | return new EmbedBlob(dvd, getEmbedConnection()); |
3810 | } catch (Throwable t) { |
3811 | throw handleException(t); |
3812 | } finally { |
3813 | if (pushStack) |
3814 | restoreContextStack(); |
3815 | } |
3816 | } |
3817 | } |
3818 | |
3819 | /** |
3820 | * JDBC 2.0 |
3821 | * |
3822 | * Get a CLOB column. |
3823 | * |
3824 | * @param columnIndex the first column is 1, the second is 2, ... |
3825 | * @return an object representing a CLOB |
3826 | */ |
3827 | public final Clob getClob(int columnIndex) throws SQLException { |
3828 | |
3829 | closeCurrentStream(); // closing currentStream does not depend on the |
3830 | // underlying connection. Do this outside of |
3831 | // the connection synchronization. |
3832 | |
3833 | checkIfClosed("getClob"); // checking result set closure does not depend |
3834 | // on the underlying connection. Do this |
3835 | // outside of the connection synchronization. |
3836 | |
3837 | synchronized (getConnectionSynchronization()) { |
3838 | int colType = getColumnType(columnIndex); |
3839 | |
3840 | // DB2:, only allow getClob on a CLOB column. |
3841 | if (colType != Types.CLOB) |
3842 | throw dataTypeConversion("java.sql.Clob", columnIndex); |
3843 | |
3844 | boolean pushStack = false; |
3845 | try { |
3846 | |
3847 | DataValueDescriptor dvd = getColumn(columnIndex); |
3848 | |
3849 | if (wasNull = dvd.isNull()) |
3850 | return null; |
3851 | |
3852 | // should set up a context stack if we have a long column, |
3853 | // since a blob may keep a pointer to a long column in the |
3854 | // database |
3855 | if (dvd.getStream() != null) |
3856 | pushStack = true; |
3857 | |
3858 | if (pushStack) |
3859 | setupContextStack(); |
3860 | |
3861 | return new EmbedClob(dvd, getEmbedConnection()); |
3862 | } catch (Throwable t) { |
3863 | throw handleException(t); |
3864 | } finally { |
3865 | if (pushStack) |
3866 | restoreContextStack(); |
3867 | } |
3868 | } |
3869 | } |
3870 | |
3871 | /** |
3872 | * JDBC 2.0 |
3873 | * |
3874 | * Get a BLOB column. |
3875 | * |
3876 | * @param columnName the column name |
3877 | * @return an object representing a BLOB |
3878 | */ |
3879 | public final Blob getBlob(String columnName) throws SQLException { |
3880 | checkIfClosed("getBlob"); |
3881 | return (getBlob(findColumnName(columnName))); |
3882 | } |
3883 | |
3884 | /** |
3885 | * JDBC 2.0 |
3886 | * |
3887 | * Get a CLOB column. |
3888 | * |
3889 | * @param columnName the column name |
3890 | * @return an object representing a CLOB |
3891 | * @exception SQLException |
3892 | * Feature not implemented for now. |
3893 | */ |
3894 | public final Clob getClob(String columnName) throws SQLException { |
3895 | checkIfClosed("getClob"); |
3896 | return (getClob(findColumnName(columnName))); |
3897 | } |
3898 | |
3899 | |
3900 | /** |
3901 | * JDBC 3.0 |
3902 | * |
3903 | * Updates the designated column with a java.sql.Blob value. The updater |
3904 | * methods are used to update column values in the current row or the insert |
3905 | * row. The updater methods do not update the underlying database; instead |
3906 | * the updateRow or insertRow methods are called to update the database. |
3907 | * |
3908 | * @param columnIndex - |
3909 | * the first column is 1, the second is 2 |
3910 | * @param x - |
3911 | * the new column value |
3912 | * @exception SQLException |
3913 | * Feature not implemented for now. |
3914 | */ |
3915 | public void updateBlob(int columnIndex, Blob x) throws SQLException { |
3916 | checksBeforeUpdateXXX("updateBlob", columnIndex); |
3917 | int colType = getColumnType(columnIndex); |
3918 | if (colType != Types.BLOB) |
3919 | throw dataTypeConversion(columnIndex, "java.sql.Blob"); |
3920 | |
3921 | if (x == null) |
3922 | updateNull(columnIndex); |
3923 | else { |
3924 | long length = x.length(); |
3925 | updateBinaryStreamInternal(columnIndex, x.getBinaryStream(), length, "updateBlob"); |
3926 | } |
3927 | } |
3928 | |
3929 | /** |
3930 | * JDBC 3.0 |
3931 | * |
3932 | * Updates the designated column with a java.sql.Blob value. The updater |
3933 | * methods are used to update column values in the current row or the insert |
3934 | * row. The updater methods do not update the underlying database; instead |
3935 | * the updateRow or insertRow methods are called to update the database. |
3936 | * |
3937 | * @param columnName - |
3938 | * the SQL name of the column |
3939 | * @param x - |
3940 | * the new column value |
3941 | * @exception SQLException |
3942 | * Feature not implemented for now. |
3943 | */ |
3944 | public void updateBlob(String columnName, Blob x) throws SQLException { |
3945 | checkIfClosed("updateBlob"); |
3946 | updateBlob(findColumnName(columnName), x); |
3947 | } |
3948 | |
3949 | /** |
3950 | * JDBC 3.0 |
3951 | * |
3952 | * Updates the designated column with a java.sql.Clob value. The updater |
3953 | * methods are used to update column values in the current row or the insert |
3954 | * row. The updater methods do not update the underlying database; instead |
3955 | * the updateRow or insertRow methods are called to update the database. |
3956 | * |
3957 | * @param columnIndex - |
3958 | * the first column is 1, the second is 2 |
3959 | * @param x - |
3960 | * the new column value |
3961 | * @exception SQLException |
3962 | * Feature not implemented for now. |
3963 | */ |
3964 | public void updateClob(int columnIndex, Clob x) throws SQLException { |
3965 | checksBeforeUpdateXXX("updateClob", columnIndex); |
3966 | int colType = getColumnType(columnIndex); |
3967 | if (colType != Types.CLOB) |
3968 | throw dataTypeConversion(columnIndex, "java.sql.Clob"); |
3969 | |
3970 | if (x == null) |
3971 | { |
3972 | updateNull(columnIndex); |
3973 | } |
3974 | else |
3975 | { |
3976 | |
3977 | long length = x.length(); |
3978 | |
3979 | updateCharacterStreamInternal( |
3980 | columnIndex, x.getCharacterStream(),length, "updateClob"); |
3981 | } |
3982 | } |
3983 | |
3984 | /** |
3985 | * JDBC 3.0 |
3986 | * |
3987 | * Updates the designated column with a java.sql.Clob value. The updater |
3988 | * methods are used to update column values in the current row or the insert |
3989 | * row. The updater methods do not update the underlying database; instead |
3990 | * the updateRow or insertRow methods are called to update the database. |
3991 | * |
3992 | * @param columnName - |
3993 | * the SQL name of the column |
3994 | * @param x - |
3995 | * the new column value |
3996 | * @exception SQLException |
3997 | * Feature not implemented for now. |
3998 | */ |
3999 | public void updateClob(String columnName, Clob x) throws SQLException { |
4000 | checkIfClosed("updateClob"); |
4001 | updateClob(findColumnName(columnName), x); |
4002 | } |
4003 | |
4004 | |
4005 | /* |
4006 | * * End of JDBC public methods. |
4007 | */ |
4008 | |
4009 | /** |
4010 | * Map a Resultset column name to a ResultSet column index. |
4011 | * |
4012 | * @param columnName |
4013 | * the name of the column |
4014 | * @return the column index |
4015 | * @exception SQLException |
4016 | * thrown on failure. |
4017 | */ |
4018 | protected int findColumnName(String columnName) |
4019 | throws SQLException { |
4020 | // n.b. if we went through the JDBC interface, |
4021 | // there is a caching implementation in the JDBC doc |
4022 | // (appendix C). But we go through our own info, for now. |
4023 | // REVISIT: we might want to cache our own info... |
4024 | |
4025 | |
4026 | if (columnName == null) |
4027 | throw newSQLException(SQLState.NULL_COLUMN_NAME); |
4028 | |
4029 | ResultDescription rd = resultDescription; |
4030 | |
4031 | // 1 or 0 based? assume 1 (probably wrong) |
4032 | // Changing the order in which columns are found from 1 till column count. |
4033 | // This is necessary in cases where the column names are the same but are in different cases. |
4034 | // This is because in updateXXX and getXXX methods column names are case insensitive |
4035 | // and in that case the first column should be returned. |
4036 | |
4037 | int columnCount = rd.getColumnCount(); |
4038 | |
4039 | for(int i = 1 ; i<= columnCount;i++) { |
4040 | String name = rd.getColumnDescriptor(i).getName(); |
4041 | if (StringUtil.SQLEqualsIgnoreCase(columnName, name)) { |
4042 | return i; |
4043 | } |
4044 | } |
4045 | throw newSQLException(SQLState.COLUMN_NOT_FOUND, columnName); |
4046 | } |
4047 | |
4048 | |
4049 | |
4050 | // |
4051 | // methods to be overridden in subimplementations |
4052 | // that want to stay within their subimplementation. |
4053 | // |
4054 | protected EmbedResultSetMetaData newEmbedResultSetMetaData(ResultDescription resultDesc) { |
4055 | return factory.newEmbedResultSetMetaData(resultDesc.getColumnInfo()); |
4056 | } |
4057 | |
4058 | /** |
4059 | * Documented behaviour for streams is that they are implicitly closed on |
4060 | * the next get*() method call. |
4061 | */ |
4062 | private final void closeCurrentStream() { |
4063 | |
4064 | if (currentStream != null) { |
4065 | try { |
4066 | // 99% of the time, the stream is already closed. |
4067 | synchronized(this) |
4068 | { |
4069 | if (currentStream != null) { |
4070 | if (currentStream instanceof java.io.Reader) |
4071 | ((java.io.Reader) currentStream).close(); |
4072 | else |
4073 | ((java.io.InputStream) currentStream).close(); |
4074 | } |
4075 | } |
4076 | } catch (IOException ioe) { |
4077 | // just ignore, caller has already read the data they require |
4078 | } finally { |
4079 | currentStream = null; |
4080 | } |
4081 | } |
4082 | } |
4083 | |
4084 | /** |
4085 | * Throw an exception if this ResultSet is closed. |
4086 | * |
4087 | * @param operation The operation the caller is trying to perform |
4088 | * |
4089 | * @exception SQLException Thrown if this ResultSet is closed. |
4090 | */ |
4091 | final void checkIfClosed(String operation) throws SQLException { |
4092 | if (isClosed) { |
4093 | throw newSQLException(SQLState.LANG_RESULT_SET_NOT_OPEN, operation); |
4094 | } |
4095 | } |
4096 | |
4097 | /** |
4098 | * Throw an exception if this ResultSet is closed or its |
4099 | * Connection has been closed. If the ResultSet has not |
4100 | * been explictly closed but the Connection is closed, |
4101 | * then this ResultSet will be marked as closed. |
4102 | */ |
4103 | final void checkExecIfClosed(String operation) throws SQLException { |
4104 | |
4105 | checkIfClosed(operation); |
4106 | |
4107 | java.sql.Connection appConn = getEmbedConnection().getApplicationConnection(); |
4108 | |
4109 | // Currently disconnected, i.e. a detached gobal transaction |
4110 | if (appConn == null) |
4111 | throw Util.noCurrentConnection(); |
4112 | |
4113 | if (appConn.isClosed()) { |
4114 | closeCurrentStream(); |
4115 | isClosed = true; |
4116 | throw Util.noCurrentConnection(); |
4117 | } |
4118 | } |
4119 | |
4120 | /** |
4121 | * Try to see if we can fish the SQL Statement out of the local statement. |
4122 | * @return null if we cannot figure out what SQL Statement is currently |
4123 | * executing |
4124 | */ |
4125 | protected String getSQLText() |
4126 | { |
4127 | if (stmt == null) |
4128 | return null; |
4129 | |
4130 | return stmt.getSQLText(); |
4131 | } |
4132 | |
4133 | /** |
4134 | * Try to see if we can fish the pvs out of the local statement. |
4135 | * @return null if we cannot figure out what parameter value set is currently |
4136 | * using |
4137 | */ |
4138 | protected ParameterValueSet getParameterValueSet() |
4139 | { |
4140 | if (stmt == null) |
4141 | return null; |
4142 | |
4143 | return stmt.getParameterValueSet(); |
4144 | } |
4145 | |
4146 | private static boolean isMaxFieldSizeType(int colType){ |
4147 | return (colType == Types.BINARY || colType == Types.VARBINARY || |
4148 | colType == Types.LONGVARBINARY || colType == Types.CHAR || |
4149 | colType == Types.VARCHAR || colType == Types.LONGVARCHAR); |
4150 | } |
4151 | /* |
4152 | * close result set if we have a transaction level error |
4153 | */ |
4154 | final SQLException closeOnTransactionError(Throwable thrownException) throws SQLException |
4155 | { |
4156 | SQLException sqle = handleException(thrownException); |
4157 | if (thrownException instanceof StandardException) |
4158 | { |
4159 | StandardException se = (StandardException) thrownException; |
4160 | int severity = se.getSeverity(); |
4161 | if (severity == ExceptionSeverity.TRANSACTION_SEVERITY) |
4162 | { |
4163 | try { |
4164 | close(); |
4165 | } catch (Throwable t) { |
4166 | SQLException top = handleException(t); |
4167 | top.setNextException(sqle); |
4168 | sqle = top; |
4169 | } |
4170 | } |
4171 | } |
4172 | |
4173 | return sqle; |
4174 | } |
4175 | |
4176 | |
4177 | /** |
4178 | Get the column value for a getXXX() call. |
4179 | This method: |
4180 | <UL> |
4181 | <LI> Closes the current stream (as per JDBC) |
4182 | <LI> Throws a SQLException if the result set is closed |
4183 | <LI> Throws a SQLException if the ResultSet is not on a row |
4184 | <LI> Throws a SQLException if the columnIndex is out of range |
4185 | <LI> Returns the DataValueDescriptor for the column. |
4186 | </UL> |
4187 | */ |
4188 | protected final DataValueDescriptor getColumn(int columnIndex) |
4189 | throws SQLException, StandardException { |
4190 | |
4191 | closeCurrentStream(); |
4192 | |
4193 | if (columnIndex < 1 || columnIndex > currentRow.nColumns()) { |
4194 | throw newSQLException(SQLState.COLUMN_NOT_FOUND, |
4195 | new Integer(columnIndex)); |
4196 | } |
4197 | if (isOnInsertRow || currentRowHasBeenUpdated && columnGotUpdated[columnIndex -1]) { |
4198 | return updateRow.getColumn(columnIndex); |
4199 | } else { |
4200 | checkOnRow(); // make sure there's a row |
4201 | return currentRow.getColumn(columnIndex); |
4202 | } |
4203 | } |
4204 | |
4205 | |
4206 | /** |
4207 | An exception on many method calls to JDBC objects does not change the state |
4208 | of the transaction or statement, or even the underlying object. This method |
4209 | simply wraps the excecption in a SQLException. Examples are: |
4210 | <UL> |
4211 | <LI> getXXX() calls on ResultSet - ResultSet is not closed. |
4212 | <LI> setXXX() calls on PreparedStatement - ResultSet is not closed. |
4213 | </UL> |
4214 | In addition these exceptions must not call higher level objects to |
4215 | be closed (e.g. when executing a server side Java procedure). See bug 4397 |
4216 | |
4217 | */ |
4218 | static final SQLException noStateChangeException(Throwable thrownException) { |
4219 | |
4220 | // Any exception on a setXXX/getXXX method does not close |
4221 | // the ResultSet or the Statement. So we only need |
4222 | // to convert the exception to a SQLException. |
4223 | |
4224 | return TransactionResourceImpl.wrapInSQLException((SQLException) null, thrownException); |
4225 | |
4226 | } |
4227 | |
4228 | /** |
4229 | A dynamic result set was created in a procedure by a nested connection. |
4230 | Once the procedure returns, there is a good chance that connection is closed, |
4231 | so we re-attach the result set to the connection of the statement the called |
4232 | the procedure, which will be still open. |
4233 | */ |
4234 | void setDynamicResultSet(EmbedStatement owningStmt) { |
4235 | |
4236 | this.owningStmt = owningStmt; |
4237 | this.localConn = owningStmt.getEmbedConnection(); |
4238 | } |
4239 | |
4240 | /* |
4241 | ** Comparable (for ordering dynamic result sets from procedures) |
4242 | */ |
4243 | |
4244 | public final int compareTo(Object other) { |
4245 | |
4246 | EmbedResultSet olrs = (EmbedResultSet) other; |
4247 | |
4248 | return order - olrs.order; |
4249 | |
4250 | } |
4251 | |
4252 | /** |
4253 | * Checks if the result set has a scrollable cursor. |
4254 | * |
4255 | * @param methodName name of the method which requests the check |
4256 | * @exception SQLException if the result set is closed or its type |
4257 | * is <code>TYPE_FORWARD_ONLY</code> |
4258 | */ |
4259 | private void checkScrollCursor(String methodName) throws SQLException { |
4260 | checkIfClosed(methodName); |
4261 | if (stmt.getResultSetType() == JDBC20Translation.TYPE_FORWARD_ONLY) |
4262 | throw Util |
4263 | .newEmbedSQLException( |
4264 | SQLState.NOT_ON_FORWARD_ONLY_CURSOR, |
4265 | new Object[] { methodName }, |
4266 | StandardException |
4267 | .getSeverityFromIdentifier(SQLState.NOT_ON_FORWARD_ONLY_CURSOR)); |
4268 | } |
4269 | |
4270 | private void checkUpdatableCursor(String operation) throws SQLException { |
4271 | if (getConcurrency() != JDBC20Translation.CONCUR_UPDATABLE) { |
4272 | throw Util.generateCsSQLException( |
4273 | SQLState.UPDATABLE_RESULTSET_API_DISALLOWED, |
4274 | operation); |
4275 | } |
4276 | } |
4277 | |
4278 | |
4279 | private boolean checkRowPosition(int position, String positionText) |
4280 | throws SQLException { |
4281 | // beforeFirst is only allowed on scroll cursors |
4282 | checkScrollCursor(positionText); |
4283 | |
4284 | synchronized (getConnectionSynchronization()) { |
4285 | setupContextStack(); |
4286 | try { |
4287 | try { |
4288 | |
4289 | /* |
4290 | * Push and pop a StatementContext around a next call so |
4291 | * that the ResultSet will get correctly closed down on an |
4292 | * error. (Cache the LanguageConnectionContext) |
4293 | */ |
4294 | LanguageConnectionContext lcc = getEmbedConnection() |
4295 | .getLanguageConnection(); |
4296 | // No timeout for this operation (use 0) |
4297 | StatementContext statementContext = |
4298 | lcc.pushStatementContext(isAtomic, |
4299 | concurrencyOfThisResultSet==JDBC20Translation.CONCUR_READ_ONLY, |
4300 | getSQLText(), |
4301 | getParameterValueSet(), |
4302 | false, 0L); |
4303 | |
4304 | boolean result = theResults.checkRowPosition(position); |
4305 | |
4306 | lcc.popStatementContext(statementContext, null); |
4307 | |
4308 | return result; |
4309 | |
4310 | } catch (Throwable t) { |
4311 | /* |
4312 | * Need to close the result set here because the error might |
4313 | * cause us to lose the current connection if this is an XA |
4314 | * connection and we won't be able to do the close later |
4315 | */ |
4316 | throw closeOnTransactionError(t); |
4317 | } |
4318 | |
4319 | } finally { |
4320 | restoreContextStack(); |
4321 | } |
4322 | } |
4323 | } |
4324 | /** |
4325 | * * Is this result set from a select for update statement? |
4326 | */ |
4327 | public final boolean isForUpdate() |
4328 | { |
4329 | if (theResults instanceof NoPutResultSet) |
4330 | return ((NoPutResultSet) theResults).isForUpdate(); |
4331 | return false; |
4332 | } |
4333 | |
4334 | final String getColumnSQLType(int column) |
4335 | { |
4336 | return resultDescription.getColumnDescriptor(column) |
4337 | .getType().getTypeId().getSQLTypeName(); |
4338 | } |
4339 | |
4340 | private final SQLException dataTypeConversion(String targetType, int column) { |
4341 | return newSQLException(SQLState.LANG_DATA_TYPE_GET_MISMATCH, targetType, |
4342 | getColumnSQLType(column)); |
4343 | } |
4344 | |
4345 | private final SQLException dataTypeConversion(int column, String targetType) { |
4346 | return newSQLException(SQLState.LANG_DATA_TYPE_GET_MISMATCH, |
4347 | getColumnSQLType(column), targetType); |
4348 | } |
4349 | |
4350 | /** |
4351 | * Mark a column as already having a stream accessed from it. |
4352 | * If the stream was already accessed, then throw an exception. |
4353 | * @param columnIndex |
4354 | * @throws SQLException |
4355 | */ |
4356 | final void useStream(int columnIndex) throws SQLException { |
4357 | |
4358 | if (streamUsedFlags == null) |
4359 | streamUsedFlags = new boolean[getMetaData().getColumnCount()]; |
4360 | |
4361 | else if (streamUsedFlags[columnIndex - 1]) |
4362 | throw newSQLException(SQLState.LANG_STREAM_RETRIEVED_ALREADY); |
4363 | |
4364 | streamUsedFlags[columnIndex - 1] = true; |
4365 | } |
4366 | |
4367 | /** |
4368 | * JDBC 4.0 |
4369 | * |
4370 | * <p> |
4371 | * Checks whether this <code>ResultSet</code> object has been |
4372 | * closed, either automatically or because <code>close()</code> |
4373 | * has been called. |
4374 | * |
4375 | * @return <code>true</code> if the <code>ResultSet</code> is |
4376 | * closed, <code>false</code> otherwise |
4377 | * @exception SQLException if a database error occurs |
4378 | */ |
4379 | public final boolean isClosed() throws SQLException { |
4380 | if (isClosed) return true; |
4381 | try { |
4382 | // isClosed is not updated when EmbedConnection.close() is |
4383 | // called, so we need to check the status of the |
4384 | // connection |
4385 | checkExecIfClosed(""); |
4386 | return false; |
4387 | } catch (SQLException sqle) { |
4388 | return isClosed; |
4389 | } |
4390 | } |
4391 | |
4392 | /** |
4393 | * Adds a warning to the end of the warning chain. |
4394 | * |
4395 | * @param w The warning to add to the warning chain. |
4396 | */ |
4397 | private void addWarning(SQLWarning w) { |
4398 | if (topWarning == null) { |
4399 | topWarning = w; |
4400 | } else { |
4401 | topWarning.setNextWarning(w); |
4402 | } |
4403 | } |
4404 | } |
4405 | |