1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.sql.GenericActivationHolder |
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.sql; |
22 | |
23 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
24 | |
25 | import org.apache.derby.iapi.types.DataValueFactory; |
26 | |
27 | import org.apache.derby.iapi.sql.execute.ExecPreparedStatement; |
28 | import org.apache.derby.iapi.sql.execute.ExecRow; |
29 | import org.apache.derby.iapi.sql.execute.ExecutionFactory; |
30 | import org.apache.derby.iapi.sql.execute.NoPutResultSet; |
31 | import org.apache.derby.iapi.sql.execute.ConstantAction; |
32 | |
33 | import org.apache.derby.impl.sql.execute.BaseActivation; |
34 | |
35 | import org.apache.derby.iapi.types.DataTypeDescriptor; |
36 | import org.apache.derby.iapi.sql.ParameterValueSet; |
37 | import org.apache.derby.iapi.sql.ResultSet; |
38 | import org.apache.derby.iapi.sql.ResultDescription; |
39 | import org.apache.derby.iapi.sql.Activation; |
40 | import org.apache.derby.iapi.sql.execute.CursorResultSet; |
41 | import org.apache.derby.iapi.sql.execute.TemporaryRowHolder; |
42 | |
43 | import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator; |
44 | import org.apache.derby.iapi.sql.dictionary.TableDescriptor; |
45 | |
46 | import org.apache.derby.iapi.reference.SQLState; |
47 | |
48 | import org.apache.derby.iapi.error.StandardException; |
49 | |
50 | import org.apache.derby.iapi.services.loader.GeneratedClass; |
51 | import org.apache.derby.iapi.services.context.Context; |
52 | |
53 | import org.apache.derby.iapi.store.access.ConglomerateController; |
54 | import org.apache.derby.iapi.store.access.ScanController; |
55 | |
56 | import org.apache.derby.iapi.types.RowLocation; |
57 | |
58 | import org.apache.derby.iapi.services.sanity.SanityManager; |
59 | |
60 | import org.apache.derby.iapi.store.access.TransactionController; |
61 | |
62 | import java.sql.SQLWarning; |
63 | import java.util.Enumeration; |
64 | import java.util.Vector; |
65 | import java.util.Hashtable; |
66 | |
67 | /** |
68 | * This class holds an Activation, and passes through most of the calls |
69 | * to the activation. The purpose of this class is to allow a PreparedStatement |
70 | * to be recompiled without the caller having to detect this and get a new |
71 | * activation. |
72 | * |
73 | * In addition to the Activation, this class holds a reference to the |
74 | * PreparedStatement that created it, along with a reference to the |
75 | * GeneratedClass that was associated with the PreparedStatement at the time |
76 | * this holder was created. These references are used to validate the |
77 | * Activation, to ensure that an activation is used only with the |
78 | * PreparedStatement that created it, and to detect when recompilation has |
79 | * happened. |
80 | * |
81 | * We detect recompilation by checking whether the GeneratedClass has changed. |
82 | * If it has, we try to let the caller continue to use this ActivationHolder. |
83 | * We create a new instance of the new GeneratedClass (that is, we create a |
84 | * new Activation), and we compare the number and type of parameters. If these |
85 | * are compatible, we copy the parameters from the old to the new Activation. |
86 | * If they are not compatible, we throw an exception telling the user that |
87 | * the Activation is out of date, and they need to get a new one. |
88 | * |
89 | * @author Jeff Lichtman |
90 | */ |
91 | |
92 | final class GenericActivationHolder implements Activation |
93 | { |
94 | BaseActivation ac; |
95 | ExecPreparedStatement ps; |
96 | GeneratedClass gc; |
97 | DataTypeDescriptor[] paramTypes; |
98 | private final LanguageConnectionContext lcc; |
99 | |
100 | /** |
101 | * Constructor for an ActivationHolder |
102 | * |
103 | * @param gc The GeneratedClass of the Activation |
104 | * @param ps The PreparedStatement this ActivationHolder is associated |
105 | * with |
106 | * |
107 | * @exception StandardException Thrown on error |
108 | */ |
109 | GenericActivationHolder(LanguageConnectionContext lcc, GeneratedClass gc, ExecPreparedStatement ps, boolean scrollable) |
110 | throws StandardException |
111 | { |
112 | this.lcc = lcc; |
113 | if (SanityManager.DEBUG) |
114 | { |
115 | SanityManager.ASSERT(gc != null, "generated class is null , ps is a " + ps.getClass()); |
116 | } |
117 | |
118 | this.gc = gc; |
119 | this.ps = ps; |
120 | |
121 | ac = (BaseActivation) gc.newInstance(lcc); |
122 | ac.setupActivation(ps, scrollable); |
123 | paramTypes = ps.getParameterTypes(); |
124 | } |
125 | |
126 | /* Activation interface */ |
127 | |
128 | /** |
129 | * @see Activation#reset |
130 | * |
131 | * @exception StandardException thrown on failure |
132 | */ |
133 | public void reset() throws StandardException |
134 | { |
135 | ac.reset(); |
136 | } |
137 | |
138 | /** |
139 | * Temporary tables can be declared with ON COMMIT DELETE ROWS. But if the table has a held curosr open at |
140 | * commit time, data should not be deleted from the table. This method, (gets called at commit time) checks if this |
141 | * activation held cursor and if so, does that cursor reference the passed temp table name. |
142 | * |
143 | * @return true if this activation has held cursor and if it references the passed temp table name |
144 | */ |
145 | public boolean checkIfThisActivationHasHoldCursor(String tableName) |
146 | { |
147 | return ac.checkIfThisActivationHasHoldCursor(tableName); |
148 | } |
149 | |
150 | /** |
151 | * @see Activation#setCursorName |
152 | * |
153 | */ |
154 | public void setCursorName(String cursorName) |
155 | { |
156 | ac.setCursorName(cursorName); |
157 | } |
158 | |
159 | /** |
160 | * @see Activation#getCursorName |
161 | */ |
162 | public String getCursorName() |
163 | { |
164 | return ac.getCursorName(); |
165 | } |
166 | |
167 | /** |
168 | * @see Activation#setResultSetHoldability |
169 | * |
170 | */ |
171 | public void setResultSetHoldability(boolean resultSetHoldability) |
172 | { |
173 | ac.setResultSetHoldability(resultSetHoldability); |
174 | } |
175 | |
176 | /** |
177 | * @see Activation#getResultSetHoldability |
178 | */ |
179 | public boolean getResultSetHoldability() |
180 | { |
181 | return ac.getResultSetHoldability(); |
182 | } |
183 | |
184 | /** @see Activation#setAutoGeneratedKeysResultsetInfo */ |
185 | public void setAutoGeneratedKeysResultsetInfo(int[] columnIndexes, String[] columnNames) |
186 | { |
187 | ac.setAutoGeneratedKeysResultsetInfo(columnIndexes, columnNames); |
188 | } |
189 | |
190 | /** @see Activation#getAutoGeneratedKeysResultsetMode */ |
191 | public boolean getAutoGeneratedKeysResultsetMode() |
192 | { |
193 | return ac.getAutoGeneratedKeysResultsetMode(); |
194 | } |
195 | |
196 | /** @see Activation#getAutoGeneratedKeysColumnIndexes */ |
197 | public int[] getAutoGeneratedKeysColumnIndexes() |
198 | { |
199 | return ac.getAutoGeneratedKeysColumnIndexes(); |
200 | } |
201 | |
202 | /** @see Activation#getAutoGeneratedKeysColumnNames */ |
203 | public String[] getAutoGeneratedKeysColumnNames() |
204 | { |
205 | return ac.getAutoGeneratedKeysColumnNames(); |
206 | } |
207 | |
208 | /** @see org.apache.derby.iapi.sql.Activation#getLanguageConnectionContext */ |
209 | public LanguageConnectionContext getLanguageConnectionContext() |
210 | { |
211 | return lcc; |
212 | } |
213 | |
214 | public TransactionController getTransactionController() |
215 | { |
216 | return ac.getTransactionController(); |
217 | } |
218 | |
219 | /** @see Activation#getExecutionFactory */ |
220 | public ExecutionFactory getExecutionFactory() |
221 | { |
222 | return ac.getExecutionFactory(); |
223 | } |
224 | |
225 | /** |
226 | * @see Activation#getParameterValueSet |
227 | */ |
228 | public ParameterValueSet getParameterValueSet() |
229 | { |
230 | return ac.getParameterValueSet(); |
231 | } |
232 | |
233 | /** |
234 | * @see Activation#setParameters |
235 | */ |
236 | public void setParameters(ParameterValueSet parameterValues, DataTypeDescriptor[] parameterTypes) throws StandardException |
237 | { |
238 | ac.setParameters(parameterValues, parameterTypes); |
239 | } |
240 | |
241 | /** |
242 | * @see Activation#execute |
243 | * |
244 | * @exception StandardException Thrown on failure |
245 | */ |
246 | public ResultSet execute() throws StandardException |
247 | { |
248 | /* |
249 | ** Synchronize to avoid problems if another thread is preparing |
250 | ** the statement at the same time we're trying to execute it. |
251 | */ |
252 | // synchronized (ps) |
253 | { |
254 | /* Has the activation class changed? */ |
255 | if (gc != ps.getActivationClass()) |
256 | { |
257 | |
258 | // ensure the statement is valid by rePreparing it. |
259 | ps.rePrepare(getLanguageConnectionContext()); |
260 | |
261 | /* |
262 | ** If we get here, it means the PreparedStatement has been |
263 | ** recompiled. Get a new Activation and check whether the |
264 | ** parameters are compatible. If so, transfer the parameters |
265 | ** from the old Activation to the new one, and make that the |
266 | ** current Activation. If not, throw an exception. |
267 | */ |
268 | GeneratedClass newGC = ps.getActivationClass(); |
269 | |
270 | BaseActivation newAC = (BaseActivation) newGC.newInstance(lcc); |
271 | |
272 | DataTypeDescriptor[] newParamTypes = ps.getParameterTypes(); |
273 | |
274 | /* |
275 | ** Link the new activation to the prepared statement. |
276 | */ |
277 | newAC.setupActivation(ps, ac.getScrollable()); |
278 | |
279 | newAC.setParameters(ac.getParameterValueSet(), paramTypes); |
280 | |
281 | |
282 | /* |
283 | ** IMPORTANT |
284 | ** |
285 | ** Copy any essential state from the old activation |
286 | ** to the new activation. This must match the state |
287 | ** setup in EmbedStatement. |
288 | ** singleExecution, cursorName, holdability, maxRows. |
289 | */ |
290 | |
291 | if (ac.isSingleExecution()) |
292 | newAC.setSingleExecution(); |
293 | |
294 | newAC.setCursorName(ac.getCursorName()); |
295 | |
296 | newAC.setResultSetHoldability(ac.getResultSetHoldability()); |
297 | if (ac.getAutoGeneratedKeysResultsetMode()) //Need to do copy only if auto generated mode is on |
298 | newAC.setAutoGeneratedKeysResultsetInfo(ac.getAutoGeneratedKeysColumnIndexes(), |
299 | ac.getAutoGeneratedKeysColumnNames()); |
300 | newAC.setMaxRows(ac.getMaxRows()); |
301 | |
302 | // break the link with the prepared statement |
303 | ac.setupActivation(null, false); |
304 | ac.close(); |
305 | |
306 | /* Remember the new class information */ |
307 | ac = newAC; |
308 | gc = newGC; |
309 | paramTypes = newParamTypes; |
310 | } |
311 | } |
312 | |
313 | String cursorName = ac.getCursorName(); |
314 | if (cursorName != null) |
315 | { |
316 | // have to see if another activation is open |
317 | // with the same cursor name. If so we can't use this name |
318 | |
319 | Activation activeCursor = lcc.lookupCursorActivation(cursorName); |
320 | |
321 | if ((activeCursor != null) && (activeCursor != ac)) { |
322 | throw StandardException.newException(SQLState.LANG_CURSOR_ALREADY_EXISTS, cursorName); |
323 | } |
324 | } |
325 | |
326 | return ac.execute(); |
327 | } |
328 | |
329 | /** |
330 | * @see Activation#getResultSet |
331 | * |
332 | * @return the current ResultSet of this activation. |
333 | */ |
334 | public ResultSet getResultSet() |
335 | { |
336 | return ac.getResultSet(); |
337 | } |
338 | |
339 | /** |
340 | * @see Activation#clearResultSet |
341 | */ |
342 | public void clearResultSet() |
343 | { |
344 | ac.clearResultSet(); |
345 | } |
346 | |
347 | /** |
348 | * @see Activation#setCurrentRow |
349 | * |
350 | */ |
351 | public void setCurrentRow(ExecRow currentRow, int resultSetNumber) |
352 | { |
353 | ac.setCurrentRow(currentRow, resultSetNumber); |
354 | } |
355 | |
356 | /** |
357 | * @see Activation#clearCurrentRow |
358 | */ |
359 | public void clearCurrentRow(int resultSetNumber) |
360 | { |
361 | ac.clearCurrentRow(resultSetNumber); |
362 | } |
363 | |
364 | /** |
365 | * @see Activation#getPreparedStatement |
366 | */ |
367 | public ExecPreparedStatement getPreparedStatement() |
368 | { |
369 | return ps; |
370 | } |
371 | |
372 | public void checkStatementValidity() throws StandardException { |
373 | ac.checkStatementValidity(); |
374 | } |
375 | |
376 | /** |
377 | * @see Activation#getResultDescription |
378 | */ |
379 | public ResultDescription getResultDescription() |
380 | { |
381 | return ac.getResultDescription(); |
382 | } |
383 | |
384 | /** |
385 | * @see Activation#getDataValueFactory |
386 | */ |
387 | public DataValueFactory getDataValueFactory() |
388 | { |
389 | return ac.getDataValueFactory(); |
390 | } |
391 | |
392 | /** |
393 | * @see Activation#getRowLocationTemplate |
394 | */ |
395 | public RowLocation getRowLocationTemplate(int itemNumber) |
396 | { |
397 | return ac.getRowLocationTemplate(itemNumber); |
398 | } |
399 | |
400 | /** |
401 | * @see Activation#getHeapConglomerateController |
402 | */ |
403 | public ConglomerateController getHeapConglomerateController() |
404 | { |
405 | return ac.getHeapConglomerateController(); |
406 | } |
407 | |
408 | /** |
409 | * @see Activation#setHeapConglomerateController |
410 | */ |
411 | public void setHeapConglomerateController(ConglomerateController updateHeapCC) |
412 | { |
413 | ac.setHeapConglomerateController(updateHeapCC); |
414 | } |
415 | |
416 | /** |
417 | * @see Activation#clearHeapConglomerateController |
418 | */ |
419 | public void clearHeapConglomerateController() |
420 | { |
421 | ac.clearHeapConglomerateController(); |
422 | } |
423 | |
424 | /** |
425 | * @see Activation#getIndexScanController |
426 | */ |
427 | public ScanController getIndexScanController() |
428 | { |
429 | return ac.getIndexScanController(); |
430 | } |
431 | |
432 | /** |
433 | * @see Activation#setIndexScanController |
434 | */ |
435 | public void setIndexScanController(ScanController indexSC) |
436 | { |
437 | ac.setIndexScanController(indexSC); |
438 | } |
439 | |
440 | /** |
441 | * @see Activation#getIndexConglomerateNumber |
442 | */ |
443 | public long getIndexConglomerateNumber() |
444 | { |
445 | return ac.getIndexConglomerateNumber(); |
446 | } |
447 | |
448 | /** |
449 | * @see Activation#setIndexConglomerateNumber |
450 | */ |
451 | public void setIndexConglomerateNumber(long indexConglomerateNumber) |
452 | { |
453 | ac.setIndexConglomerateNumber(indexConglomerateNumber); |
454 | } |
455 | |
456 | /** |
457 | * @see Activation#clearIndexScanInfo |
458 | */ |
459 | public void clearIndexScanInfo() |
460 | { |
461 | ac.clearIndexScanInfo(); |
462 | } |
463 | |
464 | /** |
465 | * @see Activation#close |
466 | * |
467 | * @exception StandardException Thrown on error |
468 | */ |
469 | public void close() throws StandardException |
470 | { |
471 | ac.close(); |
472 | } |
473 | |
474 | /** |
475 | * @see Activation#isClosed |
476 | */ |
477 | public boolean isClosed() |
478 | { |
479 | return ac.isClosed(); |
480 | } |
481 | |
482 | /** |
483 | Set the activation for a single execution. |
484 | |
485 | @see Activation#setSingleExecution |
486 | */ |
487 | public void setSingleExecution() { |
488 | ac.setSingleExecution(); |
489 | } |
490 | |
491 | /** |
492 | Is the activation set up for a single execution. |
493 | |
494 | @see Activation#isSingleExecution |
495 | */ |
496 | public boolean isSingleExecution() { |
497 | return ac.isSingleExecution(); |
498 | } |
499 | |
500 | /** |
501 | Get the number of subqueries in the entire query. |
502 | @return int The number of subqueries in the entire query. |
503 | */ |
504 | public int getNumSubqueries() { |
505 | return ac.getNumSubqueries(); |
506 | } |
507 | |
508 | /** |
509 | * @see Activation#setForCreateTable() |
510 | */ |
511 | public void setForCreateTable() |
512 | { |
513 | ac.setForCreateTable(); |
514 | } |
515 | |
516 | /** |
517 | * @see Activation#getForCreateTable() |
518 | */ |
519 | public boolean getForCreateTable() |
520 | { |
521 | return ac.getForCreateTable(); |
522 | } |
523 | |
524 | /** |
525 | * @see Activation#setDDLTableDescriptor |
526 | */ |
527 | public void setDDLTableDescriptor(TableDescriptor td) |
528 | { |
529 | ac.setDDLTableDescriptor(td); |
530 | } |
531 | |
532 | /** |
533 | * @see Activation#getDDLTableDescriptor |
534 | */ |
535 | public TableDescriptor getDDLTableDescriptor() |
536 | { |
537 | return ac.getDDLTableDescriptor(); |
538 | } |
539 | |
540 | /** |
541 | * @see Activation#setMaxRows |
542 | */ |
543 | public void setMaxRows(int maxRows) |
544 | { |
545 | ac.setMaxRows(maxRows); |
546 | } |
547 | |
548 | /** |
549 | * @see Activation#getMaxRows |
550 | */ |
551 | public int getMaxRows() |
552 | { |
553 | return ac.getMaxRows(); |
554 | } |
555 | |
556 | public void setTargetVTI(java.sql.ResultSet targetVTI) |
557 | { |
558 | ac.setTargetVTI(targetVTI); |
559 | } |
560 | |
561 | public java.sql.ResultSet getTargetVTI() |
562 | { |
563 | return ac.getTargetVTI(); |
564 | } |
565 | |
566 | /* Class implementation */ |
567 | |
568 | |
569 | /** |
570 | * Mark the activation as unused. |
571 | */ |
572 | public void markUnused() |
573 | { |
574 | ac.markUnused(); |
575 | } |
576 | |
577 | /** |
578 | * Is the activation in use? |
579 | * |
580 | * @return true/false |
581 | */ |
582 | public boolean isInUse() |
583 | { |
584 | return ac.isInUse(); |
585 | } |
586 | /** |
587 | @see org.apache.derby.iapi.sql.Activation#addWarning |
588 | */ |
589 | public void addWarning(SQLWarning w) |
590 | { |
591 | ac.addWarning(w); |
592 | } |
593 | |
594 | /** |
595 | @see org.apache.derby.iapi.sql.Activation#getWarnings |
596 | */ |
597 | public SQLWarning getWarnings() |
598 | { |
599 | return ac.getWarnings(); |
600 | } |
601 | |
602 | /** |
603 | @see org.apache.derby.iapi.sql.Activation#clearWarnings |
604 | */ |
605 | public void clearWarnings() |
606 | { |
607 | ac.clearWarnings(); |
608 | } |
609 | |
610 | /** |
611 | @see Activation#informOfRowCount |
612 | @exception StandardException Thrown on error |
613 | */ |
614 | public void informOfRowCount(NoPutResultSet resultSet, long rowCount) |
615 | throws StandardException |
616 | { |
617 | ac.informOfRowCount(resultSet, rowCount); |
618 | } |
619 | |
620 | /** |
621 | * @see Activation#isCursorActivation |
622 | */ |
623 | public boolean isCursorActivation() |
624 | { |
625 | return ac.isCursorActivation(); |
626 | } |
627 | |
628 | public ConstantAction getConstantAction() { |
629 | return ac.getConstantAction(); |
630 | } |
631 | |
632 | public void setParentResultSet(TemporaryRowHolder rs, String resultSetId) |
633 | { |
634 | ac.setParentResultSet(rs, resultSetId); |
635 | } |
636 | |
637 | |
638 | public Vector getParentResultSet(String resultSetId) |
639 | { |
640 | return ac.getParentResultSet(resultSetId); |
641 | } |
642 | |
643 | public void clearParentResultSets() |
644 | { |
645 | ac.clearParentResultSets(); |
646 | } |
647 | |
648 | public Hashtable getParentResultSets() |
649 | { |
650 | return ac.getParentResultSets(); |
651 | } |
652 | |
653 | public void setForUpdateIndexScan(CursorResultSet forUpdateResultSet) |
654 | { |
655 | ac.setForUpdateIndexScan(forUpdateResultSet); |
656 | } |
657 | |
658 | public CursorResultSet getForUpdateIndexScan() |
659 | { |
660 | return ac.getForUpdateIndexScan(); |
661 | } |
662 | |
663 | public java.sql.ResultSet[][] getDynamicResults() { |
664 | return ac.getDynamicResults(); |
665 | } |
666 | public int getMaxDynamicResults() { |
667 | return ac.getMaxDynamicResults(); |
668 | } |
669 | |
670 | } |