1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.jdbc.EmbedCallableStatement |
4 | |
5 | Copyright 1997, 2004 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.sql.ParameterValueSet; |
24 | import org.apache.derby.iapi.sql.Activation; |
25 | import org.apache.derby.iapi.error.StandardException; |
26 | import org.apache.derby.iapi.types.DataValueDescriptor; |
27 | |
28 | import org.apache.derby.iapi.services.sanity.SanityManager; |
29 | |
30 | import org.apache.derby.iapi.reference.JDBC30Translation; |
31 | import org.apache.derby.iapi.reference.SQLState; |
32 | |
33 | import java.net.URL; |
34 | import java.sql.Blob; |
35 | import java.sql.CallableStatement; |
36 | import java.sql.Clob; |
37 | import java.sql.SQLException; |
38 | import java.sql.Date; |
39 | import java.sql.Time; |
40 | import java.sql.Timestamp; |
41 | import java.util.Calendar; |
42 | |
43 | /** |
44 | * Local implementation. |
45 | * |
46 | * @author ames |
47 | */ |
48 | public abstract class EmbedCallableStatement extends EmbedPreparedStatement |
49 | implements CallableStatement |
50 | { |
51 | /* |
52 | ** True if we are of the form ? = CALL() -- i.e. true |
53 | ** if we have a return output parameter. |
54 | */ |
55 | private boolean hasReturnOutputParameter; |
56 | |
57 | protected boolean wasNull; |
58 | |
59 | /** |
60 | * @exception SQLException thrown on failure |
61 | */ |
62 | public EmbedCallableStatement (EmbedConnection conn, String sql, |
63 | int resultSetType, |
64 | int resultSetConcurrency, |
65 | int resultSetHoldability) |
66 | throws SQLException |
67 | { |
68 | super(conn, sql, false, |
69 | resultSetType, |
70 | resultSetConcurrency, |
71 | resultSetHoldability, |
72 | JDBC30Translation.NO_GENERATED_KEYS, |
73 | null, |
74 | null); |
75 | |
76 | // mark our parameters as for a callable statement |
77 | ParameterValueSet pvs = getParms(); |
78 | |
79 | // do we have a return parameter? |
80 | hasReturnOutputParameter = pvs.hasReturnOutputParameter(); |
81 | } |
82 | |
83 | protected void checkRequiresCallableStatement(Activation activation) { |
84 | } |
85 | |
86 | protected final boolean executeStatement(Activation a, |
87 | boolean executeQuery, boolean executeUpdate) |
88 | throws SQLException |
89 | { |
90 | // need this additional check (it's also in the super.executeStatement |
91 | // to ensure we have an activation for the getParams |
92 | checkExecStatus(); |
93 | synchronized (getConnectionSynchronization()) |
94 | { |
95 | wasNull = false; |
96 | ParameterValueSet pvs = getParms(); |
97 | try |
98 | { |
99 | pvs.validate(); |
100 | |
101 | } catch (StandardException e) |
102 | { |
103 | throw EmbedResultSet.noStateChangeException(e); |
104 | } |
105 | |
106 | /* KLUDGE - ? = CALL ... returns a ResultSet(). We |
107 | * need executeUpdate to be false in that case. |
108 | */ |
109 | boolean execResult = super.executeStatement(a, executeQuery, |
110 | (executeUpdate && (! hasReturnOutputParameter))); |
111 | |
112 | /* |
113 | ** If we have a return parameter, then we |
114 | ** consume it from the returned ResultSet |
115 | ** reset the ResultSet set to null. |
116 | */ |
117 | if (hasReturnOutputParameter) |
118 | { |
119 | if (SanityManager.DEBUG) |
120 | { |
121 | SanityManager.ASSERT(results!=null, "null results even though we are supposed to have a return parameter"); |
122 | } |
123 | boolean gotRow = results.next(); |
124 | if (SanityManager.DEBUG) |
125 | { |
126 | SanityManager.ASSERT(gotRow, "the return resultSet didn't have any rows"); |
127 | } |
128 | |
129 | try |
130 | { |
131 | DataValueDescriptor returnValue = pvs.getReturnValueForSet(); |
132 | returnValue.setValueFromResultSet(results, 1, true); |
133 | } catch (StandardException e) |
134 | { |
135 | throw EmbedResultSet.noStateChangeException(e); |
136 | } |
137 | finally { |
138 | results = null; |
139 | } |
140 | |
141 | // This is a form of ? = CALL which current is not a procedure call. |
142 | // Thus there cannot be any user result sets, so return false. execResult |
143 | // is set to true since a result set was returned, for the return parameter. |
144 | execResult = false; |
145 | } |
146 | return execResult; |
147 | } |
148 | } |
149 | |
150 | /* |
151 | * CallableStatement interface |
152 | * (the PreparedStatement part implemented by EmbedPreparedStatement) |
153 | */ |
154 | |
155 | /** |
156 | * @see CallableStatement#registerOutParameter |
157 | * @exception SQLException NoOutputParameters thrown. |
158 | */ |
159 | public final void registerOutParameter(int parameterIndex, int sqlType) |
160 | throws SQLException |
161 | { |
162 | checkStatus(); |
163 | |
164 | try { |
165 | getParms().registerOutParameter(parameterIndex-1, sqlType, -1); |
166 | } catch (StandardException e) |
167 | { |
168 | throw EmbedResultSet.noStateChangeException(e); |
169 | } |
170 | } |
171 | |
172 | /** |
173 | * @see CallableStatement#registerOutParameter |
174 | * @exception SQLException NoOutputParameters thrown. |
175 | */ |
176 | public final void registerOutParameter(int parameterIndex, int sqlType, int scale) |
177 | throws SQLException |
178 | { |
179 | checkStatus(); |
180 | |
181 | if (scale < 0) |
182 | throw newSQLException(SQLState.BAD_SCALE_VALUE, new Integer(scale)); |
183 | try { |
184 | getParms().registerOutParameter(parameterIndex-1, sqlType, scale); |
185 | } catch (StandardException e) |
186 | { |
187 | throw EmbedResultSet.noStateChangeException(e); |
188 | } |
189 | |
190 | } |
191 | |
192 | |
193 | /** |
194 | * JDBC 2.0 |
195 | * |
196 | * Registers the designated output parameter |
197 | * |
198 | * @exception SQLException if a database-access error occurs. |
199 | */ |
200 | public void registerOutParameter(int parameterIndex, int sqlType, |
201 | String typeName) |
202 | throws SQLException |
203 | { |
204 | throw Util.notImplemented("registerOutParameter"); |
205 | } |
206 | |
207 | |
208 | |
209 | /** |
210 | * @see CallableStatement#wasNull |
211 | * @exception SQLException NoOutputParameters thrown. |
212 | */ |
213 | public boolean wasNull() throws SQLException |
214 | { |
215 | checkStatus(); |
216 | return wasNull; |
217 | } |
218 | |
219 | /** |
220 | * @see CallableStatement#getString |
221 | * @exception SQLException NoOutputParameters thrown. |
222 | */ |
223 | public String getString(int parameterIndex) throws SQLException |
224 | { |
225 | checkStatus(); |
226 | try { |
227 | String v = getParms().getParameterForGet(parameterIndex-1).getString(); |
228 | wasNull = (v == null); |
229 | return v; |
230 | |
231 | } catch (StandardException e) |
232 | { |
233 | throw EmbedResultSet.noStateChangeException(e); |
234 | } |
235 | } |
236 | |
237 | /** |
238 | * @see CallableStatement#getBoolean |
239 | * @exception SQLException NoOutputParameters thrown. |
240 | */ |
241 | public boolean getBoolean(int parameterIndex) throws SQLException |
242 | { |
243 | checkStatus(); |
244 | try { |
245 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
246 | boolean v = param.getBoolean(); |
247 | wasNull = (!v) && param.isNull(); |
248 | return v; |
249 | } catch (StandardException e) |
250 | { |
251 | throw EmbedResultSet.noStateChangeException(e); |
252 | } |
253 | |
254 | } |
255 | |
256 | /** |
257 | * @see CallableStatement#getByte |
258 | * @exception SQLException NoOutputParameters thrown. |
259 | */ |
260 | public byte getByte(int parameterIndex) throws SQLException |
261 | { |
262 | checkStatus(); |
263 | try { |
264 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
265 | byte b = param.getByte(); |
266 | wasNull = (b == 0) && param.isNull(); |
267 | return b; |
268 | } catch (StandardException e) |
269 | { |
270 | throw EmbedResultSet.noStateChangeException(e); |
271 | } |
272 | |
273 | } |
274 | |
275 | /** |
276 | * @see CallableStatement#getShort |
277 | * @exception SQLException NoOutputParameters thrown. |
278 | */ |
279 | public short getShort(int parameterIndex) throws SQLException |
280 | { |
281 | checkStatus(); |
282 | try { |
283 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
284 | short s = param.getShort(); |
285 | wasNull = (s == 0) && param.isNull(); |
286 | return s; |
287 | } catch (StandardException e) |
288 | { |
289 | throw EmbedResultSet.noStateChangeException(e); |
290 | } |
291 | |
292 | } |
293 | |
294 | /** |
295 | * @see CallableStatement#getInt |
296 | * @exception SQLException NoOutputParameters thrown. |
297 | */ |
298 | public int getInt(int parameterIndex) throws SQLException |
299 | { |
300 | checkStatus(); |
301 | |
302 | try { |
303 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
304 | int v = param.getInt(); |
305 | wasNull = (v == 0) && param.isNull(); |
306 | return v; |
307 | |
308 | } catch (StandardException e) |
309 | { |
310 | throw EmbedResultSet.noStateChangeException(e); |
311 | } |
312 | } |
313 | |
314 | /** |
315 | * @see CallableStatement#getLong |
316 | * @exception SQLException NoOutputParameters thrown. |
317 | */ |
318 | public long getLong(int parameterIndex) throws SQLException |
319 | { |
320 | checkStatus(); |
321 | try { |
322 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
323 | long v = param.getLong(); |
324 | wasNull = (v == 0L) && param.isNull(); |
325 | return v; |
326 | } catch (StandardException e) |
327 | { |
328 | throw EmbedResultSet.noStateChangeException(e); |
329 | } |
330 | |
331 | } |
332 | |
333 | /** |
334 | * @see CallableStatement#getFloat |
335 | * @exception SQLException NoOutputParameters thrown. |
336 | */ |
337 | public float getFloat(int parameterIndex) throws SQLException |
338 | { |
339 | checkStatus(); |
340 | try { |
341 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
342 | float v = param.getFloat(); |
343 | wasNull = (v == 0.0) && param.isNull(); |
344 | return v; |
345 | } catch (StandardException e) |
346 | { |
347 | throw EmbedResultSet.noStateChangeException(e); |
348 | } |
349 | } |
350 | |
351 | /** |
352 | * @see CallableStatement#getDouble |
353 | * @exception SQLException NoOutputParameters thrown. |
354 | */ |
355 | public double getDouble(int parameterIndex) throws SQLException |
356 | { |
357 | checkStatus(); |
358 | try { |
359 | DataValueDescriptor param = getParms().getParameterForGet(parameterIndex-1); |
360 | double v = param.getDouble(); |
361 | wasNull = (v == 0.0) && param.isNull(); |
362 | return v; |
363 | } catch (StandardException e) |
364 | { |
365 | throw EmbedResultSet.noStateChangeException(e); |
366 | } |
367 | |
368 | } |
369 | |
370 | /** |
371 | * @see CallableStatement#getBytes |
372 | * @exception SQLException NoOutputParameters thrown. |
373 | */ |
374 | public byte[] getBytes(int parameterIndex) throws SQLException |
375 | { |
376 | checkStatus(); |
377 | try { |
378 | byte[] v = getParms().getParameterForGet(parameterIndex-1).getBytes(); |
379 | wasNull = (v == null); |
380 | return v; |
381 | } catch (StandardException e) |
382 | { |
383 | throw EmbedResultSet.noStateChangeException(e); |
384 | } |
385 | |
386 | } |
387 | |
388 | /** |
389 | * @see CallableStatement#getDate |
390 | * @exception SQLException NoOutputParameters thrown. |
391 | */ |
392 | public Date getDate(int parameterIndex) throws SQLException |
393 | { |
394 | checkStatus(); |
395 | try { |
396 | Date v = getParms().getParameterForGet(parameterIndex-1).getDate(getCal()); |
397 | wasNull = (v == null); |
398 | return v; |
399 | } catch (StandardException e) |
400 | { |
401 | throw EmbedResultSet.noStateChangeException(e); |
402 | } |
403 | |
404 | } |
405 | |
406 | /** |
407 | * @see CallableStatement#getTime |
408 | * @exception SQLException NoOutputParameters thrown. |
409 | */ |
410 | public Time getTime(int parameterIndex) throws SQLException |
411 | { |
412 | checkStatus(); |
413 | try { |
414 | Time v = getParms().getParameterForGet(parameterIndex-1).getTime(getCal()); |
415 | wasNull = (v == null); |
416 | return v; |
417 | } catch (StandardException e) |
418 | { |
419 | throw EmbedResultSet.noStateChangeException(e); |
420 | } |
421 | |
422 | } |
423 | |
424 | /** |
425 | * @see CallableStatement#getTimestamp |
426 | * @exception SQLException NoOutputParameters thrown. |
427 | */ |
428 | public Timestamp getTimestamp(int parameterIndex) |
429 | throws SQLException |
430 | { |
431 | checkStatus(); |
432 | try { |
433 | Timestamp v = getParms().getParameterForGet(parameterIndex-1).getTimestamp(getCal()); |
434 | wasNull = (v == null); |
435 | return v; |
436 | } catch (StandardException e) |
437 | { |
438 | throw EmbedResultSet.noStateChangeException(e); |
439 | } |
440 | } |
441 | /** |
442 | * Get the value of a SQL DATE parameter as a java.sql.Date object |
443 | * |
444 | * @param parameterIndex the first parameter is 1, the second is 2, ... |
445 | * @return the parameter value; if the value is SQL NULL, the result is |
446 | * null |
447 | * @exception SQLException if a database-access error occurs. |
448 | */ |
449 | public java.sql.Date getDate(int parameterIndex, Calendar cal) |
450 | throws SQLException |
451 | { |
452 | return getDate(parameterIndex); |
453 | } |
454 | |
455 | /** |
456 | * Get the value of a SQL TIME parameter as a java.sql.Time object. |
457 | * |
458 | * @param parameterIndex the first parameter is 1, the second is 2, ... |
459 | * @return the parameter value; if the value is SQL NULL, the result is |
460 | * null |
461 | * @exception SQLException if a database-access error occurs. |
462 | */ |
463 | public java.sql.Time getTime(int parameterIndex, Calendar cal) |
464 | throws SQLException |
465 | { |
466 | return getTime(parameterIndex); |
467 | } |
468 | |
469 | /** |
470 | * Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp |
471 | * object. |
472 | * |
473 | * @param parameterIndex the first parameter is 1, the second is 2, ... |
474 | * @return the parameter value; if the value is SQL NULL, the result is |
475 | * null |
476 | * @exception SQLException if a database-access error occurs. |
477 | */ |
478 | public java.sql.Timestamp getTimestamp(int parameterIndex, Calendar cal) |
479 | throws SQLException |
480 | { |
481 | return getTimestamp(parameterIndex); |
482 | } |
483 | |
484 | /** |
485 | * @see CallableStatement#getObject |
486 | * @exception SQLException NoOutputParameters thrown. |
487 | */ |
488 | public final Object getObject(int parameterIndex) throws SQLException |
489 | { |
490 | checkStatus(); |
491 | try { |
492 | Object v = getParms().getParameterForGet(parameterIndex-1).getObject(); |
493 | wasNull = (v == null); |
494 | return v; |
495 | |
496 | } catch (StandardException e) |
497 | { |
498 | throw EmbedResultSet.noStateChangeException(e); |
499 | } |
500 | } |
501 | /** |
502 | * JDBC 3.0 |
503 | * |
504 | * Retrieve the value of the designated JDBC DATALINK parameter as a java.net.URL object |
505 | * |
506 | * @param parameterIndex - the first parameter is 1, the second is 2 |
507 | * @return a java.net.URL object that represents the JDBC DATALINK value used as |
508 | * the designated parameter |
509 | * @exception SQLException Feature not implemented for now. |
510 | */ |
511 | public URL getURL(int parameterIndex) |
512 | throws SQLException |
513 | { |
514 | throw Util.notImplemented(); |
515 | } |
516 | |
517 | /** |
518 | * JDBC 3.0 |
519 | * |
520 | * Sets the designated parameter to the given java.net.URL object. The driver |
521 | * converts this to an SQL DATALINK value when it sends it to the database. |
522 | * |
523 | * @param parameterName - the name of the parameter |
524 | * @param val - the parameter value |
525 | * @exception SQLException Feature not implemented for now. |
526 | */ |
527 | public void setURL(String parameterName, URL val) |
528 | throws SQLException |
529 | { |
530 | throw Util.notImplemented(); |
531 | } |
532 | |
533 | /** |
534 | * JDBC 3.0 |
535 | * |
536 | * Retrieves the value of a JDBC DATALINK parameter as a java.net.URL object |
537 | * |
538 | * @param parameterName - the name of the parameter |
539 | * @return the parameter value. If the value is SQL NULL, the result is null. |
540 | * @exception SQLException Feature not implemented for now. |
541 | */ |
542 | public URL getURL(String parameterName) |
543 | throws SQLException |
544 | { |
545 | throw Util.notImplemented(); |
546 | } |
547 | |
548 | /** |
549 | * JDBC 2.0 |
550 | * |
551 | * Get a BLOB OUT parameter. |
552 | * |
553 | * @param i the first parameter is 1, the second is 2, ... |
554 | * @return an object representing a BLOB |
555 | * @exception SQLException if a database-access error occurs. |
556 | */ |
557 | public Blob getBlob (int i) throws SQLException { |
558 | throw Util.notImplemented(); |
559 | } |
560 | |
561 | /** |
562 | * JDBC 2.0 |
563 | * |
564 | * Get a CLOB OUT parameter. |
565 | * |
566 | * @param i the first parameter is 1, the second is 2, ... |
567 | * @return an object representing a CLOB |
568 | * @exception SQLException if a database-access error occurs. |
569 | */ |
570 | public Clob getClob (int i) throws SQLException { |
571 | throw Util.notImplemented(); |
572 | } |
573 | public void addBatch() throws SQLException { |
574 | |
575 | checkStatus(); |
576 | ParameterValueSet pvs = getParms(); |
577 | |
578 | int numberOfParameters = pvs.getParameterCount(); |
579 | |
580 | for (int j=1; j<=numberOfParameters; j++) { |
581 | |
582 | switch (pvs.getParameterMode(j)) { |
583 | case JDBC30Translation.PARAMETER_MODE_IN: |
584 | case JDBC30Translation.PARAMETER_MODE_UNKNOWN: |
585 | break; |
586 | case JDBC30Translation.PARAMETER_MODE_OUT: |
587 | case JDBC30Translation.PARAMETER_MODE_IN_OUT: |
588 | throw newSQLException(SQLState.OUTPUT_PARAMS_NOT_ALLOWED); |
589 | } |
590 | } |
591 | |
592 | super.addBatch(); |
593 | } |
594 | } |
595 | |